-
v0.5.0
Stablereleased this
2026-09-28 14:46:50 +00:00 | 265 commits to main since this release- Sessions live in NATS KV (
src/sessions.rs), not in memory. Every restart used to sign out every desk on the site being deployed; they now survive it, in the JetStream that is already under everything else - no new service and no new store to run. The bucket'smax_agecollects what nobody returns for, and a record's own expiry is what answers a load. - Fixed: the JetStream integration test asserted a record's projected state was one a desk move had never written to it, so it failed whenever it actually ran.
test.ymlhas been red since 0.3.47 whilepublish.ymlstayed green, which is how 0.4.0 shipped past it. - A file can come back out.
GET /attachment/{bucket}/{record}/{field}streams what atype: filefield stored, reading the object key out of the record rather than taking one from the caller - so a file is only reachable through a record somebody may see, and a key that leaks off a desk is a link to nothing. Before this, uploads were one-way: a desk showed the key as a string and there was no way to open it. - Rate limiting, per caller IP, outside everything else: a burst of 30 refilled one every two seconds (
PORTAL_RATE_BURST,PORTAL_RATE_SECONDS; either 0 turns it off). A form-filling visitor never reaches it; a script does. There was none at all before. /uploadasks the policy, like every other way in. It asked nothing: any caller who could reach the host could put 20 MB in the bucket, as often as they liked, and a site whose forms are public is a site whose upload route is public. It now takes thequestionandalternativethe file is being attached to, refuses a page that declares notype: filefield or an alternative that is closed, and asksSubmiton that page - the same question the submission itself will ask - before a byte is written. Latent until an instance had storage configured; the first one now does.- A submitter stays in dialogue with their case for as long as it runs.
self_transitiontakesfrom: [state, ...], and the access policy compiles one rule per state named; it defaulted to the initial state alone and was written that way in the compiler, so an applicant written to for a missing drawing could not send it, and nobody could withdraw once anything had happened. Omitted, it still means the initial state alone. - A record can belong to another record.
type: recordwithof: <bucket>stores the parent's id, which arrives on the link rather than being typed; a submission naming a record that is not there is refused. The other half iswhere: { field, equals }on a Kv resource, so an application's page can list the objections that name it. - A public view need not publish the whole bucket.
states: [...]on a Kv resource shows only those, for one record as well as a listing - a register that is public by law is public about what was decided, not about what was withdrawn. The desk over the same bucket is a different spec and still sees all of it. - A state can grant a group:
grants: <group>beside itsevent, so an approval that means membership does not also need somebody to remember to invite them afterwards. The lint requires the forms that fill such a bucket to collect a required name and email, because by the time a desk presses approve there is nobody left to ask. - A state can be moved by a clock:
after: { days, to }, swept hourly, measured from the record's last move (src/deadlines.rs). A deadline may only do what a person could have done -after.tois held to the same declared edge as a desk button - and the move fires the same mail and publishes the same event, stampeddeadline. - Documentation moved out of the README into
docs/: architecture, content reference, state machines, access, operations. - A page says nothing until it has something to say. The Suspense fallback on a question was the whole served page - no header, no wordmark - so the first and only thing a visitor or a crawler read was the word "loading…", which is true and is not about them. It now holds the space and stays quiet, with
aria-busyfor a reader that would otherwise find an empty document. - Gone: the
gitea_org_reposresource kind, which no site ever named.gitea_starredandgitea_releasesstay.
Downloads
- Sessions live in NATS KV (