Releases
v1.24.0
Compare
Sorry, something went wrong.
No results found
1.24.0 (2026-09-01)
Features
a11y: gate wcag 2.1 aa in ci and fix seven violations (27fb0e3 )
access-control: resolve capability to role list (61cf908 )
admin: allow changing an account role from the admin ui (4374604 )
admin: let a platform admin or org owner change sso enforcement (2079774 )
api-token: add api_token table and pepper configuration (1b65c27 )
api-token: add api-token auth middleware and rate-limit policies (1879638 )
api-token: add opt-in /api/v1 public surface disjoint from sessions (52161fc )
api-token: add repository port and drizzle implementation (23e1a12 )
api-token: add settings/api-tokens management page (b88ab0a )
api-token: add settings/tokens crud routes (fcd14d2 )
api-token: add token format primitives with crc32 checksum (a0975f5 )
api-token: add token service, di module and access-control statement (96ce2d0 )
api-token: revoke leaked tokens reported by github secret scanning (98e9a37 )
api-token: revoke org tokens when their creator loses membership (5f48721 )
api: add notification store and preference cascade (ee5e2cf )
api: add pg_notify trigger on notification insert (862c967 )
api: add put /me/locale behind its own module (23b20bd ), closes #8
api: add the back-front surface map and its parity gate (45437b5 )
api: add the sweep rail's per-request span facade (639c87e )
api: emit a domain event when notifications are marked read (22f6e95 )
api: enforce policy acceptance server-side on business routes (dd6b07d )
api: expose notification inbox and preference routes (c7d0b07 )
api: extract front-end api client call sites (0edb6e5 )
api: extract the live back-route table (b334b16 )
api: fan out notifications from the dispatch transaction (57b36dd )
api: flush batched notification emails from cron (d6b64dd )
api: honour the email frequency the notification selector promises (ea8f787 )
api: let instrumentation write attributes on the active span (f702a2a )
api: make each sweep single-flight with a lease (d57dc8a )
api: resolve notification audience from capability (36ddadd )
api: stream notification signals over sse (48e379d )
api: sweep read notifications past retention (e584ce2 )
api: trace each sweep run and pass, and stop swallowing batch errors (5ffb33f )
api: trace the sweep lease acquire and release (6d3c01a )
app: add notification bell to the app shell (f295ab9 )
app: add notification preferences page and org defaults card (354f11b )
app: add notification queries and mutations (08ade3f )
app: add notification queries and mutations (36fe208 )
app: add the admin namespace and translate the user admin screens (55e897a )
app: add the language switcher and reconcile the locale with the session (657ebf9 )
app: consume notification signals over sse (892f456 )
app: disable impersonation-forbidden actions instead of failing on click (a551320 )
app: give legal pages per-locale content modules and translated chrome (d683e39 )
app: give the policy refusal a business code and a way out (4975157 )
app: guard schema i18n keys and translate the shared request fallbacks (08045ac )
app: load more history in the notification panel (fdc367a )
app: localize api, auth and validation messages (ac57222 )
app: resolve the locale at boot and keep html lang honest (007a9c6 )
app: translate billing and format prices through intl (90b1302 )
app: translate the api tokens settings screen (f256ad9 )
app: translate the auth, account and shell surfaces (f55e157 )
app: translate the cookie consent surfaces (295f7ea )
app: translate the dashboard, org creation and invitation screens (a28083a )
app: translate the notification preference screen (4732f06 )
app: translate the org admin and audit log screens (31bf02a )
app: translate the organization forms and danger zone (01b3b97 )
app: translate the organization members and invitations surface (674eda9 )
app: translate the privacy settings screen end to end (084ed1d )
app: translate the shell chrome shared across every screen (4fc336f )
app: translate the sso settings screen (cb0ba7c )
app: translate the webhook forms and delivery detail (d39c31d )
app: translate the webhooks list and delivery tables (54407d8 )
db: store a locale on the user and on each queued email (e26fe95 )
drizzle: add notification and notification_preference tables (62c8f33 )
emails: localize per recipient and freeze the locale at enqueue (7495b6c )
emails: translate the bodies, not just the subjects (d1ee79f )
events: add api_token created, revoked and used events (5380d41 )
events: add notification map projecting the catalog onto the inbox (2c49f2e )
events: add preference audit events (catalog 65 -> 67) (193b34d )
events: add thirteen sso and scim event types (5ff52f1 )
events: add user.locale.changed (67ad13e )
events: curate the public catalog behind an explicit visibility map (82d38e8 )
i18n: add the i18n package with locale resolution (bac1528 )
i18n: add typed en/fr catalogs and the parity gate (541f1c2 )
i18n: key the plugin error codes and the field-specific validation copy (59977bd )
i18n: translate the remaining account settings cards (223a108 )
scim: emit connection and provisioning events with the integration owner as actor (064bb12 ), closes #6
sso: add sign-in entry and ship c7 (60e4346 )
sso: add the domain-based sso enforcement predicate (3ede4a3 )
sso: add the sso and scim settings page (bceffba )
sso: emit provider lifecycle and login events through the auth bridge (5921e80 )
sso: force sha256 and signed assertions on saml provider registration (3729865 )
sso: gate provider registration on the business tier and block it under impersonation (006aeff )
sso: mount sso and scim plugins with observed path constants (22ff7d9 )
sso: own sso schema file and add organization sso enforcement flag (f0e2ca6 )
sso: reject non-sso sign-in on enforced domains across all four paths (316f295 )
Bug Fixes
api-token: deny impersonated sessions on write routes (a160996 )
api-token: harden scope guard and test real pipeline in boundary tests (6aaa905 )
api-token: rehash after validity checks, pepper version from config (6373ed8 ), closes #1 #2
api-tokens: three qa defects from branch review (58d91a4 )
api-token: stop leaking moderation and billing fields on /api/v1/me (d396037 )
api-token: turn key-fetch errors into refusals and fix verify span op (c342689 )
api-token: type the revoke mock return so tsc accepts the scanning test (d6aca1b )
api: add owneruserid to actor audience resolution priority chain (2d48a20 )
api: answer not-found when a read targets someone else's notification (37d4638 )
api: assert the digest invariant, not the scheduling that produced it (271edbf )
api: bound the dry-run count and report truncation from every sweep (6630192 )
api: bound the retention sweep with a wall-clock budget (be95b30 )
api: choose what a notification payload sends to the browser (ab777df )
api: close six pre-merge findings on the sweep instrumentation rail (242677a )
api: close the rgpd-sweep race and harden the standalone cron (60492db )
api: cover remaining hand-rolled instrumentation doubles (e9213f1 )
api: emit the locale change inside the write transaction (59d1709 )
api: extend the cron's anti-starvation fix to every per-route failure (0d231d5 )
api: fail enqueue when every row is suppressed (061b8b3 )
api: fence the sweep lease by owner and use timezone-aware timestamps (24706d5 )
api: gate org-preferences reads with org permission check (521509f )
api: gate uploads and make the policy-gate documentation exact (3aa9f56 )
api: give a validation rejection an error code (a7074cc )
api: give the rgpd wipe sweep a time budget (4617b6c )
api: give the sweep lease its own unbudgeted span path (d7073ea )
api: guarantee stream unsubscribe and log sse write failures (25bd46c )
api: guard check-sweep-lock against a non-local database (3dfc47b )
api: guard email check scripts against a non-local database url (7668bbb )
api: hash idempotency key to stay under pg index 8191-byte limit (505dcc4 )
api: honour a preference flipped after a digest was scheduled (7d86ed5 )
api: keep internal-route signing fail-closed by default (b8fa8e3 )
api: make check:fanout actually fail on a broken assertion (2273033 )
api: make check:fanout run on a fresh clone and drop the hardcoded address (4872078 )
api: match tests case-insensitively in front consumer scan (ab35548 )
api: record run-level attributes on skipped and completed sweeps (cc40b00 )
api: reject the .env.example placeholder secrets in production (9bc076f )
api: remove cross-file mock.module leak in sweep-email-messages test (827df48 )
api: report processed as accounts actually attempted under truncation (140dc3a )
api: resolve each digest page in place instead of accumulating ids (834aaa9 )
api: set an explicit idle timeout on the http server (14c2791 )
api: show personal api tokens in their owner's list (6a6130d )
api: signal the read transition so the unread badge converges everywhere (452daaf )
api: stop the notification stream hub multiplying its listen connections (a879d54 )
api: stop the outbox dispatcher multiplying its listen connections (c309a79 )
api: surface notification stream hub failures to telemetry (9a2d1e4 )
api: time-bound signed internal calls and the sweep cron (f12cb54 )
api: warn when the cron's timeout override is invalid (1320c1f )
api: write a notification preference and its event in one transaction (72a285b )
app: align the shell on the pages it wraps (c9095d9 )
app: carry the auth client error code through to the toast lookup (3183687 )
app: close the locale leaks around session and boot boundaries (0ab6b3f )
app: detect a silent notification stream and reconnect (f982e92 )
app: disclose the untranslated body on every legal page (7813991 )
app: format dates in the active locale (513ba3e )
app: give the data rights link a real accessible name (ab696c7 )
app: give three pages the landmark and the heading they were missing (0574f6a )
app: keep a 4xx server message when the catalog has no copy (937ec4f )
app: keep legal route components unexported and translate the cookie captions (751d22c )
app: keep the webhook endpoint dialog inside the viewport (4793831 )
app: key every org-scoped query on the active organization (a4cc582 )
app: let the global zod map govern validation copy (c2c42d7 )
app: make impersonation freeze reason reachable without a mouse (7a9f371 )
app: make the html-lang assertion falsifiable and boot i18n resilient (ec087e8 )
app: make the repo satisfy the rule this phase made unconditional (180745a )
app: mirror the betterauth impersonation blocklist on account and security (da16f8c )
app: prove the notification category mapping and drop its cast (08a252a )
app: reach the role dialog on an account with no platform role (6ad9a55 )
app: reject stale timestamps in the webhook verification example (b1340e3 )
app: render refusals as localized copy instead of raw backend english (c9d46fb )
app: resolve remaining refusals through the error catalog (9e11de4 )
app: restore native broadcast channel semantics and fix tests (822912d )
app: restore the field-specific validation messages (9b6ed32 )
app: restore the specific auth errors and localise the rate-limit toast (1112bb1 )
app: route sso and api-token validation copy back through the catalog (8ae9485 )
app: scope chosen-locale reset to real identity changes (0aed9a0 )
app: scope the org notification defaults cache by organization (c885dc2 )
app: stop attributing a freeze to impersonation when something else owns it (b221f72 )
app: stop mixing url and path in the fr locale cookie seed (f90b68d )
app: stop the account settings crash and de-duplicate stray i18n keys (e0cf839 )
app: stop the language switcher reverting to a stale session locale (b39c7bd )
app: stop the org notification matrix overflowing its card (28df99c )
app: translate the interpolated role and status enums the extraction left raw (2d9c469 )
app: version the generated route tree so a clean clone type-checks (d01353b )
db: declare the two_factor columns better-auth writes (166d4e1 )
db: generate the migration for the user and email locale columns (4c37c18 )
db: make sso/scim migration idempotent for pre-existing drift (ae0eaa4 )
db: ship the two_factor lockout columns as a migration (18457c6 )
email: align the raw batch key separator with the template one (2b6e77b )
email: hash the chunk idempotency key instead of truncating it (98bc3e0 )
email: key idempotency per recipient rather than per batch position (f2198ea )
email: purge failed queue rows on their own retention cutoff (b6e6c84 )
email: report the row count enqueue actually wrote (06f75b1 )
emails: add api_token_leaked stub to render test (3c2e8fa )
emails: restore the emphasis on the token and organization names (642e356 )
emails: thread recipient locale through auth hooks, digest flush, and i18n fallback (8bfadfd )
emails: thread the recipient locale through every remaining send site (64db324 )
email: suppress duplicate enqueues instead of failing the batch (7b5e967 )
events: type the locale payload against the supported locale set (6fade98 )
i18n: align impersonation refusal copy with the emprunt d'identité wording (5df8252 )
i18n: correct the french a native reviewer found wrong (54f17e8 )
i18n: give the enforce aria-label a determiner in the fr catalog (c72236e )
i18n: use an invariable french header for the created-at columns (2fd0416 )
i18n: use the catalog's established "en tant que" idiom for signed-in-as (50e6d4e )
i18n: use the narrow no-break space in the acceptance toast (47b2b8f )
notifications: always set email_pending_at, even for forced events (4053d5f )
notifications: apply preferences when fanning out notifications (f0d2fac )
notifications: cap flush batch size at 5000 (90b2588 )
notifications: guard notification stream hub start against double call (ee0bc16 )
notifications: return nextcursor in notification list response (ad4cb2b )
release: stop a wrapped prose line from cutting a major version (e4d12b6 )
rgpd: enqueue the deletion confirmation inside the wipe transaction (025b49a )
rgpd: only treat the rollback sentinel as a notify failure (9c49c43 )
scim: verify the bearer token before the before-hook trusts it (0e52885 )
security: tune the global burst window to what a page view costs (b03b2b3 )
sso: close review gaps on passkey error body, sso redirect coverage, and a11y flake (70caa38 )
sso: close the scim billing bypass and key enforcement on the request (ad9056c )
sso: fail-closed rate limit for send-verification-email (8f5d500 )
sso: gate the business tier on the request's target org, not session history (8fa4e41 )
sso: normalize domain casing on both write and read paths (dc66185 )
sso: normalize domain casing on the update-provider write path too (d867c5a )
sso: normalize saml config on the update path, not just at registration (0e65850 )
sso: redirect the passkey legs into sso instead of dead-ending (bb6b120 )
sso: reject the whole sha1/md5 algorithm family, not just the bare string (4d30ab5 )
sso: resolve the org's provider deterministically and stop offering a second one (3df7c56 )
sso: stop a 404-ing scim delete from forging the actor on unrelated kicks (4ad2970 )
test: restore stub payload parse to success:true in outbox mock (a9160bb )
toolchain: align dockerfiles and docs with node 24.20.0/bun 1.4.0/pnpm 11.24.0 (40fb4db )
ui: bound modal height at the primitive instead of per dialog (50830a2 )
uploads: delete the replaced object when an avatar changes (314dbef )
Performance
email: collapse marksent into a single statement (03c8445 )
Refactor
api-token: turn the public api into an injectable factory (358b926 )
api: drop the unused session-based /me route (7d97b4c )
api: enforce the required sweep lock at runtime, not just in types (e569a7d )
api: extract and test the sweep cron's outcome classification (14baf70 )
api: give check-sweep-lock a fresh span facade per check (da2e8b1 )
api: move the six sweep routes onto the shared instrumented purge (bf5d257 )
api: promote the batched sweep delete into one instrumented helper (ce12453 )
api: promote the profile store port to the shared kernel (44df0e5 )
api: replace sweep as-sql casts with a named requirefilter guard (4233736 )
api: return an option for the queued email locale (b9fe7c0 )
api: scope the sweep lock's schema lookup to function bodies (88e3e92 )
api: separate app construction from server boot (07e850f )
api: use the tolocale helper in the scanning route (a66e184 )
app: bind the display locale inside the date formatters (6db7cd0 )
app: let the router plugin own code-splitting (76cc583 )
app: move the route tree to file-based routing (9a9094a )
app: narrow zod issues on their discriminant instead of casting (00fb798 )
app: point every policy title at the shared map (ef4b2e3 )
app: promote broadcast channel into a generic primitive (0c8bcc6 )
app: share one policy-title map and drop a guard nothing calls (46c9644 )
emails: derive template props from the template catalog (8276340 )
i18n: move the sub-processor labels to the namespace that owns them (5ae0ad6 )
notifications: move channel/frequency/scope constants to @packages/events (853e9ea )
sweep: promote the retention runner to n passes (e81864a )
Build
db: move postgres to 18-alpine (c6b251f )
ddd-kit: emit declarations via tsc instead of tsup's bundled dts (fbcbdb8 ), closes #4
deps: move to typescript 7 and refresh the dependency floor (9aa37ca )
toolchain: align pnpm and bump node, bun, pnpm to current (2aeab0d ), closes package.json#packageManager
Documentation
add d3 to the module inventory and the architectural log (5e658ea )
api-token: complete documentation pass for phase c.4 (da664c6 )
api-token: record c.4 as-built and the public-surface rules (a021340 )
api: move subsystem rules out of the always-loaded context (7dba32b )
api: reword the drizzle mock's overclaimed exhaustiveness note (1bf2416 )
api: write the public api reference for token holders (201ada1 )
app: shrink the i18n carve-out to what still ships literals (e658676 )
bring every document back to the as-built state (2970f57 )
claude: correct the runtime floors to match engines (e526eac )
claude: state the real i18n boundary and the shared-front contracts (5173928 )
correct event counts and fill two inventory gaps (d78a9cf )
correct the surface map counts to the as-built numbers (0e0f9f1 )
correct two stale docblocks (3fdfecb )
cron: document the sweep lease and the three nested deadlines (2b5cb38 )
cron: document the sweep rail's trace shape and span budget (cab996c ), closes #2
cron: document the un-nested shutdown bound and the upgrade path (54c2312 )
cron: record the lease/attribute fixes and the measured span truncation (54c1aa7 )
db: fix remaining postgres 17 prose and warn about the volume-mount move (700cc30 )
declare the two retention knobs, and correct the audit-page counts (d9760ed )
email: describe both retention passes for email_message sweep (745e86d )
fix factual errors in the email queue debt closeout entry (9289ca7 )
fix stale claims left around the event rail (265b52f )
i18n: declare the locale cookie and record the e1a decisions (3d9204a )
i18n: record the e1b extraction and retire the partial-translation carve-out (0fbd89e )
modules: promote 7 roadmap phases to shipped and recompute subtotals (7947f54 )
move e1b out of the backlog and use measured figures (7112a68 )
notifications: document the notification map projection (8053e4a )
point the inventory line at the public api reference (afd1997 )
readme: mark c7 sso + scim as shipped (5bb75c5 )
record d3 notification center as shipped (70a60e2 )
record the d5 email queue debt closeout (1daca8d )
record the e1a i18n foundation across the doc set (6f7af16 )
record the h1 surface parity audit and correct the e1b policy claim (12d4d27 )
roadmap: add phase g.1 toolchain refresh (afba410 )
roadmap: add the back/front parity audit and renumber the sweep backlog (26eac5f )
roadmap: correct c.4 spec and add public-surface curation to c.5 (dec49aa )
roadmap: record g1 as shipped (2081044 ), closes #1
roadmap: settle phase d.3 design and defer d.2 (f6101be ), closes #6
roadmap: update event catalog count 65->67 (fc69b7b )
sso: correct the superseded passkey enforcement claim in history (0d28a74 )
sso: record the final fix round and its accepted gaps (30c5ba0 )
sso: record the post-pr security review round (f911663 )
You can’t perform that action at this time.