Changelog
Latest
New endpoints
createRecord: create a record with an auto-generated TID rkey instead of requiring the caller to supply oneapplyWrites: batch multiple create, update, and delete operations in a single request
Optimistic concurrency
swapRecord: optional CID-based concurrency guard onputRecord,deleteRecord, and individual operations withinapplyWrites. Returns409 Conflictwhen the record's current CID doesn't match.swapCommit: optional revision-based concurrency guard onapplyWrites. Asserts the space's current revision before applying any writes. Returns409 Conflicton mismatch.- Spaces now track a
revisionfield (TID) that advances on every write.
Space DID separation
- Spaces now have their own
didfield, distinct from theowner_didof the space creator. For personal spaces these are the same DID; multi-party spaces will have their own DID. - All URI construction and lookups use the space's DID. Ownership checks use
owner_did. - New database migration adds the
didcolumn to thespacestable.
Two-step credential flow
- Replaced the single
getCredentialendpoint with a two-step flow:getMemberGrant: proves membership and returns an HMAC-SHA256 grant (5-minute TTL)getSpaceCredential: exchanges the grant for an ES256 space credential JWT (4-hour TTL)
- Removed the
refreshCredentialendpoint (just repeat the two-step flow)
Bearer auth for space credentials
- Space credentials are now passed as standard
Authorization: Bearer <token>instead of a customX-Space-Credentialheader. HappyView distinguishes credentials from other Bearer tokens by checking the JWTtypheader (space_credential), matching Dan's reference implementation. - No DPoP auth or client key needed when authenticating via space credential.
Endpoint naming
- Space CRUD endpoints renamed to verbNoun format:
space.create→space.createSpace,space.get→space.getSpace,space.list→space.listSpaces,space.update→space.updateSpace,space.delete→space.deleteSpace. - Invite endpoints moved out of the
invite.*sub-namespace:invite.create→space.createInvite,invite.redeem→space.redeemInvite,invite.revoke→space.revokeInvite,invite.list→space.listInvites. - Old endpoint names are still available as legacy aliases and will be removed in a future release.
Bug fixes
- Fixed
WriteOpserde deserialization.swapRecordfields inupdateanddeleteoperations now correctly deserialize from camelCase JSON. - Credential
issclaim now uses the space's DID instead of the owner's DID. SpaceUriparsing updated to usedid(space DID) instead ofowner_did.
v2.5.0
Released 2026-05-05
Initial release of Permissioned Spaces behind the feature.spaces_enabled experimental flag.
Features
- Space CRUD:
create,get,list,update,delete - Record operations:
putRecord,getRecord,listRecords,deleteRecord - Membership management:
addMember,removeMember,listMembers - Invite system:
invite.create,invite.redeem,invite.revoke,invite.list ats://URI scheme for addressing permissioned data- Access model with
default_allow/default_denymodes and app allowlists/denylists - Space credentials for cross-service read access via
X-Space-Credentialheader - Delegation: adding a space as a member transitively grants access to its members
- Lua scripting context includes space metadata (
space.did,space.owner_did,space.type_nsid,space.skey)