The server now applies a registry write to the running settings itself and
says how it went in the set response: a top-level "x:settingsReload" of
{"applied": true} or {"applied": false, "description": "Saved, but the
running settings were not reloaded. <object>: <error>"}, absent when the
write needs no reload. Sending ReloadSettings after it is a second reload
per burst of saves, and a refused one only repeats what the server said.
The JMAP client now hands the listener each written type with the server's
report, when there is one. A write that carries it queues nothing: applied
removes that reload from what's pending (the server's reload came after
every earlier write of that kind), and a refusal queues it as known
unapplied, as a failed reload from the admin would, without sending it.
A write without the report is an older server's, and queues the admin's
reload as before. When the burst settles there is still one result: the
admin's reload decides it when it had to send one; otherwise a "Saved and
applied" toast, or the banner with the server's reason and the object it
named, and "Apply now" sending ReloadSettings. A later write the server
applies clears an earlier refusal.
"Saved and applied" stays for settings objects; a directory or the default
authentication, which the server also reloads, keeps its form's own toast.
The type table follows the server's list of what each write needs. Alert,
DnsServer, Enterprise and SpamLlm are read when used, and MetricsStore and
TracingStore are stores, so they need no reload; the admin sent one for
each. Allowed IPs are part of the full settings, but the server answers an
AllowedIp write with the blocked-IP reload, which doesn't rebuild them, so
for those the admin still sends ReloadSettings whatever the report says.
New string, in src/i18n/en.json (the only catalogue) under settingsApply:
notReloaded, shown when a refusal comes without a description.
A registry write is stored at once, but the running server only picks up
most settings when it rebuilds its configuration, which it does on a write
for directories and the default authentication alone. Everything else, a
delivery schedule for one, sat unapplied until someone ran Management >
Actions > Reload > Server settings by hand.
Every x:<Type>/set now goes past a listener in the JMAP client. A write that
changed a settings object queues the reload action it needs, and once no
write has been in flight for 600 ms the queued actions go out together in
one x:Action/set. A bulk edit or a page that saves several objects in a row
costs one reload, not one per object; a save still in flight holds the
reload back however long it takes.
Which action a type needs lives in lib/settingsApply.ts. Certificates, lookup
stores and blocked IPs have their own reload actions, and the full settings
reload doesn't rebuild them. Directories and authentication, data read live
or kept current by cache invalidation (accounts, domains, DKIM keys, tenants,
roles, lists and the like), operations and records, and stores, which a
reload never reopens, get none. A type the list doesn't know is reloaded: an
unneeded reload costs a second, a missing one leaves a setting unapplied. If
the server later applies these writes by itself, this becomes one extra,
harmless reload per burst of saves.
Applying straight after a save is safe because a reload is all or nothing:
the new configuration replaces the running one only when every settings
object builds. When one doesn't, the server keeps what it had and names the
object and the problem. That now shows as a banner above the page, "Saved,
but the server couldn't apply the settings: <reason>", naming the object with
a link to it, and an Apply now button. It stays until a reload succeeds or it
is dismissed. A failure that is already known is not retried on unrelated
saves, only on Apply now or a save that needs a reload.
On success a "Saved and applied" toast replaces the form's own "Saved
successfully" and "Created successfully" for settings objects, so a save
shows one message, not two.
New strings, in src/i18n/en.json (the only catalogue) under settingsApply:
applied, applyNow, dismiss, failed, failedObject, noAnswer, notConfirmed,
openObject, stillRunning.
inbuxa-server renames the identifiers that carried the upstream name
(its SPEC.md §2.4): upstream's JMAP capability for the registry (x:)
objects is urn:inbuxa:jmap:registry, beside the fork's own urn:inbuxa:jmap,
and the web interface it serves signs in as inbuxa-webui. There are no
aliases, so this lands with the server change and deploys with it.
Publishing the source is what asks for it: a modified version has to carry
prominent notices saying it was modified, with a date. These files already
added a Coffey Labs copyright line beside upstream's, which implies as much
without saying it; now they say it.
38 files, found by diffing against the merge base with upstream rather than
by guessing. Upstream's own notices are untouched. The build is unchanged.
The palette and light/dark choice now live in the account's JMAP Files
(ihasmail/settings.json), the same file and keys INBUXA webmail uses, so
the theme follows the user across devices and both apps. The admin
reads it at sign-in and writes only palette, mode and the derived
legacy theme, after a fresh read, keeping every other key. A palette
change keeps the stored mode. localStorage stays as the first-paint
cache.