|
1 | 1 | # everything-dev |
2 | 2 |
|
| 3 | +## 2.0.0-rc.44 |
| 4 | + |
| 5 | +### Patch Changes |
| 6 | + |
| 7 | +- 07765ba: auth: admin member management no longer depends on the admin's own organization membership (#876 follow-up) |
| 8 | + |
| 9 | + `adminAddMember` forwarded the caller's headers into Better Auth's `addMember`, which checks the |
| 10 | + caller's **organization** permissions — so a platform admin who was not a member of the target |
| 11 | + organization (the whole point of an admin route) got FORBIDDEN. The mutation is now a direct write, |
| 12 | + like every other mutation in `AdminOrganizationsService`: it enforces the organization membership |
| 13 | + limit through the plugin's membership policy and refuses duplicate memberships. The integration |
| 14 | + suite now covers adding a member to an organization the admin does not belong to — the case the |
| 15 | + previous tests masked by creating every fixture organization owned by the admin. |
| 16 | + |
| 17 | + Two smaller consistency fixes ride along: |
| 18 | + |
| 19 | + - `adminUpdateMemberRole` refuses to demote an organization's **only owner** to a non-owner role, |
| 20 | + matching `adminRemoveMember`'s existing last-owner guard. |
| 21 | + - `getOrganizationForAdmin` guards with the standard `requireAdmin` middleware instead of a |
| 22 | + hand-rolled role check, matching the admin routes' pattern. |
| 23 | + |
| 24 | + `crossSubDomainCookies` (#668) also gained config-time warnings for the two ways a shared cookie |
| 25 | + domain fails silently at the browser: a `domain` that does not cover the app's own `baseUrl` host |
| 26 | + (browsers drop the cookie outright, breaking sign-in) and localhost/loopback base URLs (browsers |
| 27 | + refuse `Domain` attributes there). The auth plugin README now documents the full multi-app recipe — |
| 28 | + shared cookie domain + shared `BETTER_AUTH_SECRET` + shared `postgres://` `AUTH_DATABASE_URL` — |
| 29 | + mirroring the ADR 0027 decomposition. |
| 30 | + |
| 31 | +- a19b559: Auth plugin surfaces cross-subdomain cookie configuration (#668). New authored variable under `auth.variables`: `crossSubDomainCookies: { enabled, domain }`, mapped to Better Auth's `advanced.crossSubDomainCookies`. When enabled, session cookies carry `Domain=<domain>` so a multi-app family on sibling subdomains (`app.example.com`, `activity.example.com`) shares one session — by config alone, no local auth code. `domain` must be a dot-prefixed registrable domain (`.example.com`) when enabled; without it Better Auth falls back to the base URL's root domain. Absent or disabled config leaves cookies host-scoped (behavior unchanged). Sharing a cookie domain requires every app on it to run the same `BETTER_AUTH_SECRET` — the sealed cookie is decrypted with it — plus sibling `trustedOrigins` entries. |
| 32 | +- ed70afd: auth: stop creating duplicate personal organizations when metadata or slug drifts off the canonical form (#877) |
| 33 | + |
| 34 | + `findPersonalOrganization` matched only the byte-exact pair `slug = userId AND metadata = '{"isPersonal":true}'`, |
| 35 | + while the lenient `isPersonalOrganization()` predicate accepted either signal. An organization whose metadata |
| 36 | + was non-canonical JSON (pretty-printed, extra keys) or whose slug had been renamed was invisible to the finder, |
| 37 | + so the `user.create` hook silently created a second personal organization on the next signup/session — observed |
| 38 | + in production as users with multiple personal orgs plus dangling `user.last_active_organization_id` / |
| 39 | + `session.active_organization_id` pointers. |
| 40 | + |
| 41 | + The finder now resolves the personal organization with the lenient signals: |
| 42 | + |
| 43 | + - `slug = userId` (unchanged), or |
| 44 | + - metadata containing a top-level `"isPersonal": true` flag **and** the user holds a membership in that organization. |
| 45 | + |
| 46 | + Matches are deterministic (`created_at asc, id asc`, limit 1), so historical duplicates converge on the oldest row |
| 47 | + instead of generating new ones. `ensurePersonalOrganization` still writes the canonical metadata string on create; |
| 48 | + nothing about creation changes. |
| 49 | + |
| 50 | + Two deliberate hardenings beyond the literal issue proposal: |
| 51 | + |
| 52 | + - The metadata signal is matched with a text pattern, not `metadata::jsonb->>'isPersonal'`. The column is |
| 53 | + `text` and better-auth stores raw strings when callers pass non-object metadata, so a bare cast would throw |
| 54 | + on malformed rows — inside the `user.create` hook, that breaks every signup on the deployment. |
| 55 | + - The metadata branch is bound to the user through a membership check. An unbounded `metadata isPersonal OR slug` |
| 56 | + predicate would let any user's lookup match any other user's personal-flagged organization. |
| 57 | + |
| 58 | + The orphan sweep keeps its strict canonical-only deletion query on purpose: widening it to the lenient signals |
| 59 | + would delete non-canonical organizations that may hold user data. |
| 60 | + |
| 61 | +- 9da8ed9: Boot the pinned host, not the parent's newest bytes (#874): the orchestrator |
| 62 | + resolves the host slot's `digest` and registers the manifest from the pin's |
| 63 | + immutable coordinates — a root publish can no longer move the host bytes a |
| 64 | + pinned child boots. `mf check` probes the same pin. When a pinned host's |
| 65 | + shared singletons still cannot resolve in the image, the boot fails with the |
| 66 | + skew named — image version, pin, and `bos upgrade && bos deploy` — instead of |
| 67 | + a bare package error. |
| 68 | +- 350beba: Revert the regression harness's file-backed pglite substitution: the dev stack |
| 69 | + opens the auth database from two processes (the auth service and the auth-plugin |
| 70 | + instance composed into the api/host), and a per-secret shared data dir turned |
| 71 | + that topology into ADR 0044's silent-corruption case — the suite died on |
| 72 | + system-catalog reads past EOF (`pg_attribute`, "unexpected data beyond EOF"). |
| 73 | + The harness is restored to in-memory pglite, whose per-process databases made |
| 74 | + the dual-open harmless. App fixtures for regression specs still seed over HTTP; |
| 75 | + a file-backed mode needs a single-writer story first (seed through the running |
| 76 | + stack, not pre-spawn against shared files). |
| 77 | +- Updated dependencies [59cfe70] |
| 78 | + - every-plugin@3.0.0-rc.18 |
| 79 | + |
3 | 80 | ## 2.0.0-rc.43 |
4 | 81 |
|
5 | 82 | ### Minor Changes |
|
0 commit comments