Changelog
All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog.
[1.2.0] 2026-08-17 Security (1)
Security release with a behaviour change to can(). Read the item below before upgrading — permission checks that used to pass may now fail, and that is the point.
Security
-
can()now fails closed: only an explicit booleantruegrants access (src/user-manager.ts:266). The check wasget(this.permissions, permission)evaluated for truthiness, so any truthy leaf granted the permission — including values that were never intended as a grant.can("posts")returnedtruewhenpermissions.postswas the nested object{ create: false, delete: false }(a non-empty object is truthy), i.e. a permission map that denies everything granted the parent permission. The same held for"0","false",1, a non-empty array, or any object a server happened to send in that slot. The comparison is now=== true.This is a behaviour change and it can deny users who were previously allowed. If your permissions come from an API that sends
1/0,"true"/"false", or nested objects, normalize them to real booleans beforesetUserData/update, or overridecan()in yourUsersubclass. The default is deliberately the strict one: an authorization check that guesses is worse than one that says no, because the failure is silent and grants access rather than withholding it.
[1.1.6] 2026-05-26 Added (7) · Fixed (4) · Changed (1)
Added
- Marketing-style
README.mddocumenting the full public API:Userbase class,UserEventsListener,setCurrentUser/getCurrentUser,UserInterface,UserInfo,UserCacheDriverInterface. - AI-agent skill cards under
skills/covering the user manager, cache drivers, events, permissions, the current-user pointer, and end-to-end recipes. llms.txtandllms-full.txtfor LLM-facing documentation discovery.- Vitest suite under
src/__tests__/covering login/logout transitions, access-token handling, dot-notation get/set, cache driver hydration onboot(), permissions checks, and event triggers. vitest.config.ts(Node environment) with monorepo-aware sibling resolution.- GitHub Actions CI workflow at
.github/workflows/test.ymlrunning the matrix Node 18 / 20 / 22 on Ubuntu plus Node 20 on Windows. package.json:sideEffects: false,scripts.test/scripts.test:watch,description, expandedkeywords, anddevDependenciesforvitestandtypescript.
Fixed
UserEventsListener.onBoot()now subscribes to theboottopic (previously subscribed tologout, so callbacks registered viaonBootnever fired from a real boot). (src/user-events-listener.ts:16)UserEventsListener.onKeyChange()now subscribes to thekeyChangetopic (previously subscribed tologout). (src/user-events-listener.ts:53)User.update()now emits the correct previous value asoldValuetokeyChangelisteners. Previouslythis.userDatawas reassigned before the per-key loop ran, sothis.get(key)inside the loop returned the new value, makingoldValueidentical tonewValue. The previous data is now captured before the assignment and indexed inside the loop. (src/user-manager.ts:170-174)User.update()no longer mutates the caller’suserDataargument. The input is now cloned at the top of the method, so writing the preserved access token back is done on the clone rather than the caller’s object. (src/user-manager.ts:163)
Changed
getCurrentUser()now returnsUser | undefinedinstead ofUser. The runtime always returnedundefinedbeforesetCurrentUserwas called; the type now reflects that. Consumers must handle the undefined case (e.g.getCurrentUser()?.isLoggedIn()or anif (user)guard). (src/current-user.ts:3,19)