Repository navigation
Releases: gombit-dev/gombit
Release list
v0.8.0
v0.8.0
Manual: action required
-
Breaking. Every write refuses a float that is not finite (
+Inf,-Inf,NaN), or beyond afloat32field's range, with a 422 on that field. (floats-must-be-finite, behavior, #449)It was stored on PostgreSQL and SQLite (and a 500 on MySQL). Code
that stored a non-finite float on purpose in a column it never
returns as JSON now gets a*database.ValidationError: store NULL
(a pointer orsql.NullFloat64) instead. A row that already stores
one keeps working for partial updates of other columns and for an
admin edit that leaves the column alone, but a genericSaveof it
is a 422 on that field until the column is set to a finite value or
NULL (docs/database.md § Floats). -
Breaking.
upgradeis a framework command, and a reserved management-command name. (reserved-upgrade-command, cli, #341)An app that registers its own
upgradecommand loses it: the
framework's is added first, and Cobra resolves to it. Rename the
app's command (and itsinternal/<pkg>/commands.goregistration). -
Breaking.
gombit contract apprefuses a framework replaced by a fork, and ago.modthe go command refuses. (contract-app-fork-unresolved, cli, #341)A
replaceofgithub.com/gombit-dev/gombitby another module used
to report the fork's version as the framework's; it is now
unresolved, like a local path. Ago.modrequiring the framework
twice, or replacing it twice with different targets, is an error.
The replace that counts is the one the go command applies to the
required version (an exact-version replace over an every-version
one; a replace of another version does not apply), so a go.mod
carrying several replaces can report a different version, or
resolve where it used to fail. Build the contract against a
framework release. -
Breaking. Every write refuses text a column cannot store the same way on every driver (a NUL byte, invalid UTF-8, more than the column holds), with a 422 on that field. (
text-storable-on-every-driver, behavior, #444)It was a 500 on PostgreSQL or MySQL and stored on SQLite. A
size:n/varchar(n)column holds n characters, atextcolumn
65,535 bytes (MySQL'sTEXT), and an unsized primary-key, indexed,
unique or defaulted string 191 characters (MySQL'svarchar(191)),
now on every driver: PostgreSQL and SQLite stored more. A row that
already stores such text stays editable through the admin, its form
included, and partial updates (database.ScopeEditwith
database.StoredValuesjudges only what an edit changes); a generic
Saveof it is a 422 on that field until the value is shortened or
cleaned (docs/database.md § Text). -
Breaking.
database.Searchtakes a context and returns an error, likeFilterEq: a search term with a NUL byte or invalid UTF-8 is a 422. (database-search-takes-context, api, #444)Code calling
database.Search(q, columns, term)no longer builds:
calldatabase.Search(ctx, q, columns, term)and return its error.
Rungombit generateto update an app's generatedhandler.gen.go,
which also answers agetof an id overMaxInt64with a 404. -
A scaffolded
internal/product/handler.goanswers an id overMaxInt64with a 404; an app scaffolded before answers a 500 on PostgreSQL. (scaffolded-get-id-over-maxint64, scaffold, #444)The handler is app-owned, so
gombit generatedoes not update it. In
itsget, parse the id withstrconv.ParseUint(input.ID, 10, 63)
instead of64: PostgreSQL's bigint cannot bind a larger id, and no
row holds one. Apply the same to any hand-written handler that
parses a uint id. -
Breaking. With auth enabled, an app that registers the session routes, the
auth-*session operation IDs or theAuthSession/AuthRevokeResultschema names fails at startup: the framework registers them. (auth-session-names-reserved, api, #335)With
GOMBIT_JWT_SECRETset, registering a route atGETor
DELETE {prefix}/auth/sessionsorDELETE {prefix}/auth/sessions/{id}
(through Huma or the raw Gin router), an operation
auth-list-sessions,auth-revoke-sessionorauth-revoke-sessions,
or a type Huma namesAuthSession,DataListAuthSession,
AuthRevokeResultorDataAuthRevokeResultnow panics when the app
starts. Drop the app's own session routes, which the framework's
replace, or rename them. A resource namedSession
(gombit make resource Session) does not collide. -
Breaking. With auth enabled, a
GOMBIT_JWT_REFRESH_TTLshorter thanGOMBIT_JWT_ACCESS_TTLfails config validation, so the app does not start. (refresh-ttl-at-least-access-ttl, config, #335)- Configuration:
GOMBIT_JWT_REFRESH_TTL: some values are now refused. - Configuration:
GOMBIT_JWT_ACCESS_TTL: some values are now refused.
The refresh token's lifetime is the session's, and an access token
must not outlive its session: it would stop authenticating when the
session ends while itsexp,expires_inand access cookie still
promised more. Config validation (config.Load/Validate) and
auth.NewServicerefuse that pair; equal TTLs are fine. Raise
GOMBIT_JWT_REFRESH_TTLto at leastGOMBIT_JWT_ACCESS_TTL, or
lowerGOMBIT_JWT_ACCESS_TTL. An access token also ends with its
session: it stops authenticating when the session expires, not only
when it is revoked, so a token issued before the upgrade under the
old TTLs stops at its session's expiry, before itsexp. - Configuration:
Automatic: applied by the upgrade tooling
-
gombit newrecords the app's upgrade baseline in agombit:block ofgombit.yaml. (record-upgrade-baseline, scaffold, actionrecord-baseline, #341)An app generated before records none, and is detected as scaffold
version 0.gombit upgrade baseline --writerecords it.
Informational
-
config.Loadreads a.envfile whole: a line longer than 64 KiB no longer silently stops it, so the assignments after one now apply. (dotenv-long-lines, config)Before, the first line over 64 KiB ended the read without an
error, and every variable after it kept its process-environment
or default value. If a.envhas such a line, check the values
set after it. -
An admin relation field on a string key stores the string sent, byte for byte; a JSON number for it is a 422. (
admin-relation-string-keys, behavior, #452)A numeric-looking key (
"123","007") was stored corrupted. A
client that sends a string key as a JSON number now gets a 422 on the
field, as for any string field: send it as a string. A uuid key must
be the canonical form, as auuidfield (no braces, with hyphens).
An integer key still accepts a number or its digits as a string. -
An admin PATCH writes only the columns it (or a model hook) changed, never associations, and answers 404 for a row deleted meanwhile. (
admin-patch-writes-changes-only, behavior, #450)It used to save the whole loaded row: a concurrent change to another
column was reverted, a deleted row came back, andhas_many
children were written back.database.ScopeEditnow narrows any
Select("*")update of the scoped row the same way. -
On Windows,
gombit make resourcereplaces files with a POSIX-semantics rename, so a file open with delete sharing no longer blocks it. (make-resource-windows-posix-rename, cli, #341)On a volume that refuses that rename (FAT or exFAT, a network share
or mapped drive, a\\wsl$path, or Windows before 10 1709) it keeps
its previous plain rename and its rollback. -
database.KeepStoredZerosis deprecated: usedatabase.ScopeEditwithdatabase.StoredValues. (keep-stored-zeros-deprecated, api, #444)ScopeEditjudges an edit of a loaded row on what it changes,
compared after the model's hooks, for the text check as well as
stored zero instants.KeepStoredZeroskeeps working. -
MapPersistErrorandMapLoadErroranswer a database data exception (a value too long or out of range for its column) with a 422 instead of a 500. (data-exceptions-are-422, behavior, #444)PostgreSQL 22001, 22003, 22007, 22008, 22021, 22P05 and MySQL 1264,
1265, 1292, 1366, 1406 (database.IsDataException). A uint list
filter overMaxInt64is a 422 too. -
Session management in both auth modes:
GET {prefix}/auth/sessionslists the user's active sessions;DELETE {prefix}/auth/sessions/{id}andDELETE {prefix}/auth/sessions?scope=others|allrevoke them. (auth-session-management, api, #335)auth.ServicegainsListSessions(returning[]auth.AuthSession),
RevokeSession,RevokeAllSessionsandErrSessionNotFound. Cookie
mode clears the session cookies when a request ends its own session
(docs/auth.md § Sessions). -
A refresh token revoked by logout or session revocation is a 401 that no longer revokes the user's other sessions; only an already-rotated token counts as reuse. (
refresh-reuse-only-rotated-tokens, security, #335) -
POST /auth/refreshanswers 500, not 401, when the database fails while the rotation locks the user's row (a deadlock, a lock timeout, a lost co...
v0.7.1
What's Changed
- fix(cache): treat a non-positive janitor interval as no janitor by @leo-aa88 in #553
- fix(cache): refuse to overflow in the memory driver's Increment by @leo-aa88 in #555
- fix(framework): answer unknown paths and recovered panics with D10 errors by @leo-aa88 in #556
- fix(contract): answer an unencodable response with a D10 500 by @leo-aa88 in #559
- fix(database): log through the app's logger, never with parameter values in the SQL by @leo-aa88 in #557
- fix(contract): saturate PageOffset instead of wrapping by @leo-aa88 in #558
- fix(database): never store a decimal changed; respond with the stored row by @leo-aa88 in #560
- fix(database): refuse timestamps and dates no driver can store and return, on every write by @leo-aa88 in #562
- bench: refresh microbench snapshot after PERF-6 by @leo-aa88 in #565
Full Changelog: v0.7.0...v0.7.1
v0.7.0
What's Changed
- fix: stop crash redelivery after MaxAttempts by @SamCT86 in #525
- Add @Brunotlps as a code owner by @leo-aa88 in #533
- [STORAGE-1] Storage abstraction by @leo-aa88 in #522
- fix: retry each failed job once per invocation by @SamCT86 in #534
- [STORAGE-2] Local and in-memory drivers by @leo-aa88 in #523
- build(deps): bump github.com/go-sql-driver/mysql from 1.8.1 to 1.10.1 by @dependabot[bot] in #540
- build(deps): bump github.com/mattn/go-sqlite3 from 1.14.28 to 1.14.52 by @dependabot[bot] in #536
- [STORAGE-3] S3-compatible driver by @leo-aa88 in #524
- [STORAGE-4] Secure upload API primitives by @leo-aa88 in #526
- fix(admin): reject composite primary keys at Register by @tnalbant in #542
- [STORAGE-5] Public/private objects and signed URLs by @leo-aa88 in #527
- test: make staticcheck nil guards explicit by @SamCT86 in #541
- [STORAGE-6] Direct browser-to-storage upload flow by @leo-aa88 in #528
- fix(config): reject trust-all proxy CIDR combinations in production by @rupayon123 in #518
- [STORAGE-7] Object metadata and lifecycle/cleanup semantics by @leo-aa88 in #529
- fix(benchmarks): name raw k6 summaries by framework and benchmark by @leo-aa88 in #543
- [MODEL-8] Storage-backed field kinds (file, image) by @leo-aa88 in #531
- fix(benchmarks): judge the host before publishing a snapshot as canonical by @leo-aa88 in #544
- fix(benchmarks): record the CRUD protocol per unit by @leo-aa88 in #545
- fix(framework): deliver the handler's timeout response when HTTP.RequestTimeout is set by @leo-aa88 in #546
- fix(framework): give stop hooks their own shutdown budget by @leo-aa88 in #547
- fix(framework): keep text after a stray "<" when a value also has a real tag by @leo-aa88 in #548
- fix(framework): count requests that panic in the HTTP metrics by @leo-aa88 in #549
- [STORAGE-8] Admin integration for storage-backed fields by @leo-aa88 in #532
- fix(framework): give every embedded HTML page the browser security policy by @leo-aa88 in #550
- fix(framework): release what New and Run opened when they fail by @leo-aa88 in #551
- docs: bring the README, agent guides, and user docs up to date with storage by @leo-aa88 in #561
New Contributors
- @tnalbant made their first contribution in #542
- @rupayon123 made their first contribution in #518
Full Changelog: v0.6.1...v0.7.0
v0.6.1
What's Changed
- fix(cli): accurate help text and reserve every framework command name by @leo-aa88 in #447
- docs: bring reference docs up to date with v0.6.0 by @leo-aa88 in #429
- fix: avoid repeated client generation for unchanged specs by @charle-z in #517
- docs: bring the README, changelog, and docs index up to v0.6.0 by @leo-aa88 in #428
- docs: add the Claude Code onboarding skill by @Brunotlps in #520
- fix: preserve caller options in DispatchAt by @SamCT86 in #521
New Contributors
Full Changelog: v0.6.0...v0.6.1
v0.6.0
What's Changed
Full Changelog: v0.5.0...v0.6.0
v0.5.0
v0.4.0
What's Changed
- fix: derive admin fields from the generated contract by @leo-aa88 in #399
- feat: plan and gate destructive schema changes before a migration is written (SCHEMA-2) by @leo-aa88 in #402
- feat: first-class table rename that keeps rows and the registry valid (SCHEMA-3) by @leo-aa88 in #403
- feat: gombit db lint and repair, with acknowledgements persisted in migrations (SCHEMA-4) by @leo-aa88 in #404
- feat: deletion is the database's deletion — hard delete (SCHEMA-5) by @leo-aa88 in #405
- [SCHEMA-6] gombit db check — single schema-integrity gate by @leo-aa88 in #406
Full Changelog: v0.3.1...v0.4.0
v0.3.1
What's Changed
Full Changelog: v0.3.0...v0.3.1
v0.3.0
What's Changed
- feat: share one logical field vocabulary by @leo-aa88 in #392
- feat: generate uuid, json, date, and float fields by @leo-aa88 in #393
- feat: field constraints for default, bounds, length, and regex by @leo-aa88 in #394
- feat: generate email, url, slug, and ip fields by @leo-aa88 in #395
- feat: one-to-one, nullable, and self-referential relations by @leo-aa88 in #396
- feat: configurable integer or UUID primary keys by @leo-aa88 in #397
- feat: duration, time of day, and enum labels by @leo-aa88 in #398
- ci(release): install Node deps before the release test gate by @leo-aa88 in #400
Full Changelog: v0.2.1...v0.3.0
v0.2.1
What's Changed
- build(deps): bump gorm.io/driver/postgres from 1.6.2 to 1.6.3 by @dependabot[bot] in #380
- fix(bench): key run-crud rows and provenance on (framework, benchmark) (#361) by @Brunotlps in #371
- fix: migration model-tracking papercuts — --forget-model + make-resource determinism (#300) by @leo-aa88 in #378
- feat: data-preserving column rename for makemigrations — --rename (#299) by @leo-aa88 in #379
Full Changelog: v0.2.0...v0.2.1