Skip to content

v1.24.0

Choose a tag to compare

@github-actions github-actions released this 01 Sep 17:34
· 3 commits to main since this release

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)