ab-ecosystem-sso 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -4
- package/dist/ab-ecosystem-sso.cjs +28 -28
- package/dist/ab-ecosystem-sso.js +4175 -4044
- package/dist/index.d.ts +116 -6
- package/dist/style.css +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -523,11 +523,39 @@ openAccountSettings({
|
|
|
523
523
|
});
|
|
524
524
|
```
|
|
525
525
|
|
|
526
|
-
- **Members** — list active or revoked members; edit a member's role and access expiry; revoke access. Revoking leaves their login alone: only this account becomes unreachable, from their next request onward, and re-inviting the same person restores the membership.
|
|
526
|
+
- **Members** — for an **owner**, list active or revoked members; edit a member's role and access expiry; revoke access. Revoking leaves their login alone: only this account becomes unreachable, from their next request onward, and re-inviting the same person restores the membership.
|
|
527
527
|
- **Roles** — create, edit and delete roles with a permission list (one per line). The server trims, uppercases, dedupes and sorts permissions (max 200), and they aren't validated against a catalogue yet, so a misspelled string simply grants nothing. **System** roles are assignable but neither editable nor deletable, and a role still held by anyone can't be deleted.
|
|
528
528
|
- **Invitations** — create invites (email, member/user, role, access expiry), filter by status, and revoke pending ones. After creating one, the link is shown **once** with a copy button — the token is never returned again and no email is sent.
|
|
529
529
|
|
|
530
|
-
|
|
530
|
+
### Owners and members see different things
|
|
531
|
+
|
|
532
|
+
The modal works out which side the signed-in person is on from `context.act` in `GET /me`, and renders accordingly — no prop needed:
|
|
533
|
+
|
|
534
|
+
| | Members | Roles | Invitations |
|
|
535
|
+
| --- | --- | --- | --- |
|
|
536
|
+
| **Owner** | full administration | ✅ | ✅ |
|
|
537
|
+
| **Team member** | their team, read-only | hidden | hidden |
|
|
538
|
+
|
|
539
|
+
A member's **Members** tab lists their colleagues and each one's role from `GET /account/team`, headed by which account they're in and the role they hold themselves. Roles and Invitations are hidden for them rather than shown and then refused — those endpoints are owner-only and would answer `"Only the account owner can do this"`, which the owner-side sections still display as-is if a non-owner ever reaches them.
|
|
540
|
+
|
|
541
|
+
Detection is deliberately cautious: only an explicit `act` of `"member"` or `"user"` counts as a member. An unrecognised value, or no `context` at all, is treated as the owner — the behaviour from before per-member sessions existed. Override it with `isOwner` if you already know, and hide the three sections entirely with `showTeamSections={false}`.
|
|
542
|
+
|
|
543
|
+
### Account context
|
|
544
|
+
|
|
545
|
+
The same `context` block is useful outside the modal — it says which account the session is in, the member's role, and what that role grants:
|
|
546
|
+
|
|
547
|
+
```ts
|
|
548
|
+
import { getAccountContext, hasPermission } from "ab-ecosystem-sso";
|
|
549
|
+
|
|
550
|
+
const ctx = await getAccountContext(projectId);
|
|
551
|
+
// { accountId, act, isOwner, role: { id, title, version }, permission,
|
|
552
|
+
// accessExpiry, accountName, accountEmail } — or null when there's no context
|
|
553
|
+
|
|
554
|
+
if (!ctx?.isOwner) showMemberUi(ctx?.role?.title);
|
|
555
|
+
if (hasPermission(ctx, "CHAT.TRANSFER")) enableTransfer();
|
|
556
|
+
```
|
|
557
|
+
|
|
558
|
+
`hasPermission` is case-insensitive, passes owners everything, and returns `true` when there's no context — so it degrades to "unrestricted" rather than locking people out of an app that hasn't adopted roles yet. Permission strings aren't validated against a catalogue server-side, so a misspelled one simply never matches.
|
|
531
559
|
|
|
532
560
|
The three panels are also exported for use in your own admin page:
|
|
533
561
|
|
|
@@ -597,7 +625,8 @@ const [open, setOpen] = useState(false);
|
|
|
597
625
|
| `syncUrlHash` | `boolean` | Mirror open state + active section in the URL hash. Default `true`. See [URL hash & refresh](#url-hash--refresh). |
|
|
598
626
|
| `title` | `string` | Modal heading. Default `"Settings"`. |
|
|
599
627
|
| `mode` | `"light" \| "dark"` | Colour scheme. Default `"light"`. See [Light & dark mode](#light--dark-mode). |
|
|
600
|
-
| `isOwner` | `boolean` |
|
|
628
|
+
| `isOwner` | `boolean` | Overrides owner-vs-member detection. Omitted ⇒ read from `context.act` in `GET /me`. |
|
|
629
|
+
| `showTeamSections` | `boolean` | `false` hides Members / Roles / Invitations entirely. Default `true`. |
|
|
601
630
|
| `inviteLinkBase` | `string` | Where invite links point; the token is appended as `?token=…`. Default `<origin>/accept-invite`. |
|
|
602
631
|
| `onAccountSwitch` | `({ accessToken, accountId }) => void` | Enables the **Accounts** switcher. Store the fresh token in place of the old one. |
|
|
603
632
|
| `currentAccountId` | `string` | Marked "Current" in the switcher. |
|
|
@@ -893,6 +922,8 @@ Beyond the components, these functions are exported for building custom UIs:
|
|
|
893
922
|
| `listRolesApi` · `createRoleApi` · `updateRoleApi` · `deleteRoleApi` | `/account/roles` (owner only) |
|
|
894
923
|
| `listInvitationsApi` · `createInvitationApi` · `revokeInvitationApi` | `/account/invites` (owner only) |
|
|
895
924
|
| `listMembersApi` · `updateMemberApi` · `revokeMemberApi` | `/account/members` (owner only) |
|
|
925
|
+
| `listTeamApi(projectId, token?, apiBaseUrl?)` | `GET /account/team` → `TeamMember[]` — the caller's colleagues, for a **member** |
|
|
926
|
+
| `getAccountContext(projectId, token?, apiBaseUrl?)` | `GET /me` → `AccountContext \| null` (owner vs member, role, permissions) |
|
|
896
927
|
| `validateSession(projectId, token, apiBaseUrl?)` | `GET /me` → `{ valid, accountAccessLost, message, code }` |
|
|
897
928
|
| `logout(options)` | `POST /auth/logout` + callbacks |
|
|
898
929
|
| `logoutApi(projectId, token, apiBaseUrl?)` | `POST /auth/logout` |
|
|
@@ -917,7 +948,8 @@ import type {
|
|
|
917
948
|
AccountOption, SelectAccountRequest, AccessTokenResponse, InvitationLookup, SessionValidation,
|
|
918
949
|
Role, CreateRolePayload, UpdateRolePayload,
|
|
919
950
|
Invitation, InvitationStatus, CreateInvitePayload, CreatedInvite,
|
|
920
|
-
Member, MemberStatus, UpdateMemberPayload,
|
|
951
|
+
Member, MemberStatus, UpdateMemberPayload, TeamMember,
|
|
952
|
+
AccountContext, AccountRoleRef,
|
|
921
953
|
TokenStorageConfig, TokenStorageKind,
|
|
922
954
|
AuthFetchInit, AuthHandlers, AuthInterceptorOptions, UnauthorizedInfo,
|
|
923
955
|
SsoRoutePaths, SsoScreen, SsoRouteMatch, SsoRouteObject,
|