Releases: sufforest/vela
Release list
v0.3.0
[0.3.0] — 2026-06-27
A sandboxed WebAssembly extension platform, plus a round of federation,
end-to-end-encryption, and client-compatibility hardening.
Added
- Extension platform. Sandboxed WebAssembly plugins (wasmtime + the
Component Model) hook the server at well-defined points without forking it.
Decision points —check_registration,check_login,check_media_upload,
check_profile_update,check_room_create— allow / deny / modify a
request;on_eventobserves events asynchronously;filter_sync_event
shapes what a client sees in/sync; inbound federated events can be
soft-failed by a plugin. Plugins get three capabilities — structured
logging, anemit-eventbot channel, and per-plugin key/value state — all
behind a manifest whose grants are reconciled against the component's actual
imports before it loads. Per-plugin fuel, memory, and wall-clock limits;
hot-reload on SIGHUP. Ships an SDK and example plugins. - Third-party protocols + matrix-rtc transports.
GET /_matrix/client/v3/thirdparty/protocolsand the MSC4143rtc/transports
discovery endpoint.
Security
/keys/queryno longer leaks other users'user_signing_keys— they
are returned only for a self-query, per spec. (Cross-user leakage corrupted
the client trust model and showed verified users as untrusted.)/preview_urlSSRF guard. The URL-preview fetch refuses targets that
resolve to private/internal addresses, re-validates each redirect hop, pins
the connection to the validated address, and caps the response body.
Operators with internal preview targets opt out via
[media] url_preview_allow_private_ips.- Cross-signing signature uploads are scoped to the caller — a client can
no longer fold signatures attributed to another user, or into another user's
device/signing keys (cross-user signing is limited to the master key). The
cross-signing-key UIA gate keys off key material, not signatures. - Cap federation response bodies (key server 256 KiB, general 100 MiB).
Fixed
- Federation signing keys. Refetch a remote server's keys when a signature
references an unknown key id instead of serving a stale cached key; accept
events signed with a server's rotated-out keys within their validity window. - E2EE / devices. Preserve cross-signing signatures across a key re-upload
(a verified device no longer reverts to unverified); track device
last_seen; deliver to-device messages delete-on-ack on both/syncand
sliding sync (a dropped sync can't lose a verification request); notify a
user's other devices and room-mates when a device is deleted. - Client compatibility. Stop a
/syncbusy-loop on lazy-loaded
incremental syncs; emit the MSC4222state_afterunder the key matching the
client's opt-in param (rooms no longer render as "v1"/empty in Element);
keep room heroes' membership through lazy-load (fixes "Empty room" on fresh
login); align the/loginwell_knownbase URL with discovery; return
M_UNRECOGNIZEDfor auth-metadata when delegated auth is off.
v0.2.0
[0.2.0] — 2026-06-13
Spec-maturity milestone: faster joins (MSC3706/MSC3902), delegated auth
(MSC3861), extended profiles (MSC4133), notifications history, dehydrated
devices (MSC3814), and a long tail of CS-API / federation correctness work.
Added
-
Dehydrated devices (MSC3814).
PUT/GET/DELETE /_matrix/client/unstable/org.matrix.msc3814.v1/dehydrated_deviceplus
POST .../{device_id}/eventslet a client park an encrypted, offline
device on the server and rehydrate it later to decrypt to-device room keys
that arrived while it was away. The dehydrated device is registered like
any other device, so/keys/query,/keys/claim, to-device routing, and
cross-serverm.device_list_updateall work for it; the events endpoint
drains its to-device queue with a read-ahead cursor. One per user — a new
upload replaces and purges the previous one;device_dataand one-time-key
counts are bounded, and a dehydrated id may not alias an existing device. -
Notification history.
GET /_matrix/client/v3/notificationsreturns a
paginated list of past notifications (withfrom/limit/only=highlight).
Rows are persisted whenever a push rule matches for a local recipient — even
when no push gateway is registered — and thereadflag is computed at query
time from the user'sm.readreceipt /m.fully_readmarker. -
Extended profile fields (MSC4133).
GET/PUT/DELETE /_matrix/client/v3/profile/{userId}/{keyName}for arbitrary profile fields
(timezone, pronouns, …) alongside the standarddisplayname/avatar_url;
the full-profile response folds them in. Owner-only writes, size-bounded. -
GET /_matrix/client/v1/auth_metadata(MSC2965). Relays the configured
IdP's OAuth authorization-server metadata, falling back to an issuer-only
document if the IdP is unreachable; 404 when delegated auth is off. -
Faster remote joins (MSC3706 + MSC3902 partial state). Joining a
large federated room no longer blocks on downloading its full member
list. vela requests a join withomit_members=true, becomes joinable
immediately with a partial-state hint, and a background filler
reconciles the rest of the room state and device lists out of band.
/syncsurfacespartial_state: trueso clients can soft-fail
membership-dependent features until the room resolves; endpoints that
need complete state (/members,/joined_members,/state,
/state_ids, inboundmake/send_joinandmake/send_knock) block or
reject while a room is still partial rather than serving incomplete
answers. The filler mirrors member transitions and the remote
device-key cache on re-verify, replays bufferedm.device_list_update
EDUs once full state lands, and re-evaluates events optimistically
accepted or soft-failed during the partial window. -
Delegated authentication via OIDC / OAuth2 (MSC3861, phase 2). vela
can defer login to an external identity provider instead of managing
passwords itself. Set[auth.oidc].introspection_endpointand vela
validates Bearer tokens by introspecting them against the IdP (RFC 7662,
client_secret_basic/client_secret_post), caches results up to two
minutes bounded by the token's own expiry, and provisions accounts on
first touch from thesub/username/device_idclaims. When
enabled, the legacy auth surface is refused:/loginadvertises no
password flow,/registerrejects non-AS callers, and
/account/password//account/deactivatereturnM_UNRECOGNIZED. -
Stateful sliding sync (MSC4186). The
/syncsuccessor persists
per-connection state in a newsliding_sync_connscolumn family.
Reconnects no longer re-deliver state the client already has; the
server emits room data only for rooms that crossed a list window,
visibility, or state version since the last poll (DELTA ops), and
explicit room subscriptions stay live across polls until the client
drops them (sticky subscriptions). -
Matrix Application Service support. Bridges (mautrix-telegram,
mautrix-discord, mautrix-signal, etc.) and bots can now register
with vela. An operator pastes the AS's registration YAML into the
admin room via!as register <yaml>; vela validates the
namespaces, hashes the tokens (cleartext is shown to the operator
once, never stored), persists to a newappservicesCF, and
starts a per-AS outbound delivery worker. Every event matching the
AS's namespaces is enqueued into the newappservice_outboxCF;
the worker drains it, posts toPUT /_matrix/app/v1/transactions/ {txnId}withAuthorization: Bearer <hs_token>, falls back to
the legacy/transactions/{txnId}URL on 404/405, and retries
with exponential backoff (2s → 5min cap, 24h dead threshold).
InboundBearer <as_token>+?user_id=masquerades the request
as a user in the AS's namespace — virtual users are provisioned
on demand. Admin commands:!as register/list/unregister/enable/ disable. Interest filter is wired into both the local send path
andfederation_receive, so federated events trigger AS delivery
too. Deferred to follow-ups:m.login.application_service
register/login types,M_EXCLUSIVEenforcement on non-AS callers,
ping protocol, query endpoints,?ts=timestamp massaging,
ephemeral passthrough (m.presence/m.typing/m.receipt under
receive_ephemeral), device management UIA bypass, third-party
protocols. -
Delayed events (MSC4140). Clients can schedule an event to be sent
after a delay (self-destructing status, scheduled posts). A
[server] max_delay_msknob caps how far out a delay may be set. -
Event relationships over federation (MSC2836).
/event_relationshipswalks and backfills threaded and related events
across servers, so clients see complete relation chains for rooms whose
history spans multiple homeservers. -
Owned state events (MSC3757). State events whose
state_keyis a
user's own MXID can be set by that user regardless of power level,
enabling per-user state without granting elevated permissions. -
Server-side invite filtering (MSC4155). An invitee's
org.matrix.msc4155.invite_permission_configaccount data drives
which invites vela accepts on their behalf, so unwanted invites are
rejected before they ever reach the client. -
Restricted-room joins over federation. vela can complete the
send_joinhappy path for restricted rooms, joining via a third
server that vouches for the join authorisation. -
Notary server-key proxy.
/_matrix/key/v2/queryanswers questions
about other servers' keys: vela fetches the target's
/key/v2/server, countersigns it, and returns the result, acting as a
key-notary for peers. -
Room summary (MSC3266).
GET /_matrix/client/v1/rooms/{roomIdOrAlias}/summary
(and theim.nheko.summaryunstable path) lets clients preview a room
before joining. Resolves aliases, gates visibility via the existing
peek rules (members/invitees always; otherwise public/knock/
world-readable/allow-list), returns the caller'smembership, and
serves unauthenticated requests for world-readable rooms only. Rooms we
don't host are summarised over federation (the hierarchy root from a
via/ known candidate server), so previewing a remote room works for
authenticated callers. -
Intentional mentions (MSC3952).
m.mentionsis now honoured for
push:.m.rule.is_user_mentionnotifies a user listed in
content.m.mentions.user_ids, and.m.rule.is_room_mentionhandles
@room— but only when the sender's power level meets the room's
notifications.roomthreshold, so low-power users can't @room-spam.
Highlight counts in/syncreflect the same rules. -
Batch device delete.
POST /_matrix/client/v3/delete_devices
with the same UIA discipline as single-device delete; ids the caller
doesn't own are skipped instead of failing the whole batch. -
Content reporting.
POST /_matrix/client/v3/rooms/{roomId}/report/{eventId}
plus the v1.13/rooms/{roomId}/reportand v1.14
/users/{userId}/reportsiblings. v1.18 semantics: optional
reason, noscore. Always returns 200{}(privacy mode —
doesn't leak whether the target exists or the reporter is in the
room). Reports persist into a newevent_reportsCF. -
?server=on/publicRooms. GET/POST/_matrix/client/v3/publicRooms
now accept theserverquery param. When set to a remote homeserver
name, vela forwards the request via
POST /_matrix/federation/v1/publicRoomsand returns the peer's
response. Clients can browse other homeservers' directories without
having to talk to them directly. -
/.well-known/matrix/support. Serves admin/security contacts and
a support page from a new[support]config section (MSC1929);
returns 404 when unconfigured. -
m.get_login_tokencapability advertised as disabled so clients
hide the cross-device-login affordance we don't implement. -
vela-admin rooms-topanddiagnose.rooms-top --limit Nlists
rooms by most-recent activity with a relative-age column (clock-skewed
future bumps render asfuture);diagnoseis a one-screen operator
health probe covering current stream position, rooms still mid
partial-state resync, destinations with pending outbound queues, and
24h / 7d room activity. Both read existing schema, no new state. -
Admin bot commands
!reports [N](show the last N abuse reports,
default 20),!reactivate <mxid>(undo!deactivate's flag), and
!reset-password <mxid> [password](atomic: fresh argon2 hash, clear
the deactivated flag, revoke every access token; generates a random
password when none is given). -
Complement in CI. The Matrix spec-compliance suite now runs on
every PR via.github/workflows/complement.yml. Image build is
cached through buildkit's GHA backend; the existing
tools/testing/complement/{run.sh,skiplist.txt}runner is reu...