ab-ecosystem-sso 0.1.8 → 0.1.10
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 +151 -51
- package/dist/ab-ecosystem-sso.cjs +24 -24
- package/dist/ab-ecosystem-sso.js +862 -840
- package/dist/index.d.ts +92 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,11 +1,29 @@
|
|
|
1
1
|
# ab-ecosystem-sso
|
|
2
2
|
|
|
3
|
-
Drop-in React auth & account UI for the partner-ecosystem **Auth-as-a-Service** backend — login, signup, forgot-password,
|
|
3
|
+
Drop-in React auth & account UI for the partner-ecosystem **Auth-as-a-Service** backend. Ships production-ready screens — login (with 2FA), signup, forgot-password, session validation, and a full **Account Settings** modal (profile, wallet, plans & add-ons, credit wallets) — all wired to the `/api/v1/projects/:projectId/...` endpoints, plus low-level helpers (`getUser`, `logout`, `useSession`) for building your own UI.
|
|
4
4
|
|
|
5
|
-
- ⚛️ React 18 / 19
|
|
6
|
-
- 🎨 Self-contained, theme-aware
|
|
7
|
-
- 🔌
|
|
8
|
-
- 🧩
|
|
5
|
+
- ⚛️ React 18 / 19, shipped as ESM + CJS with full TypeScript types.
|
|
6
|
+
- 🎨 Self-contained, theme-aware CSS that **won't leak into or be overridden by** your app.
|
|
7
|
+
- 🔌 Use it declaratively (`<AccountSettings />`) or imperatively (`openAccountSettings()`).
|
|
8
|
+
- 🧩 Every network call also available as a plain function for custom UIs.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Table of contents
|
|
13
|
+
|
|
14
|
+
- [Installation](#installation)
|
|
15
|
+
- [Configuration basics](#configuration-basics)
|
|
16
|
+
- [Auth screens](#auth-screens) — `Login` · `Signup` · `ForgotPassword`
|
|
17
|
+
- [Session management](#session-management) — `SessionProvider`, enforce subscription
|
|
18
|
+
- [Account Settings modal](#account-settings-modal) — `openAccountSettings` / `AccountSettings`
|
|
19
|
+
- [Logout](#logout) — `logout` · `LogoutButton` · `logoutApi`
|
|
20
|
+
- [Fetching the current user](#fetching-the-current-user) — `getUser`
|
|
21
|
+
- [Fetching user data](#fetching-user-data) — `getUserProfile` · `getUserWallet` · `getUserCreditWallet` · `getUserSubscription`
|
|
22
|
+
- [Two-factor setup](#two-factor-setup)
|
|
23
|
+
- [Hooks](#hooks)
|
|
24
|
+
- [Theming](#theming)
|
|
25
|
+
- [API reference](#api-reference)
|
|
26
|
+
- [TypeScript](#typescript)
|
|
9
27
|
|
|
10
28
|
---
|
|
11
29
|
|
|
@@ -15,35 +33,35 @@ Drop-in React auth & account UI for the partner-ecosystem **Auth-as-a-Service**
|
|
|
15
33
|
npm install ab-ecosystem-sso
|
|
16
34
|
```
|
|
17
35
|
|
|
18
|
-
`react` and `react-dom`
|
|
36
|
+
`react` and `react-dom` (v18 or v19) are **peer dependencies** — install them in your app.
|
|
19
37
|
|
|
20
38
|
### Import the stylesheet once
|
|
21
39
|
|
|
22
|
-
The components ship a single CSS file. Import it once at your app's entry point:
|
|
23
|
-
|
|
24
40
|
```ts
|
|
25
41
|
import "ab-ecosystem-sso/styles.css";
|
|
26
42
|
```
|
|
27
43
|
|
|
28
|
-
|
|
44
|
+
The CSS is scoped (a `[data-aas]` root + the `sso:` utility prefix) and shipped **unlayered**, so it never touches your app's elements and your app's resets (e.g. Tailwind's preflight) never override it. No extra `@layer` setup needed.
|
|
29
45
|
|
|
30
46
|
---
|
|
31
47
|
|
|
32
|
-
## Configuration
|
|
48
|
+
## Configuration basics
|
|
33
49
|
|
|
34
|
-
|
|
50
|
+
Almost everything takes the same three inputs:
|
|
35
51
|
|
|
36
|
-
|
|
|
52
|
+
| Input | Description |
|
|
37
53
|
| --- | --- |
|
|
38
|
-
| `projectId` | Your project id, e.g. `436582-forms.abprojects.com`. Required
|
|
39
|
-
| `token` | The auth JWT
|
|
40
|
-
| `apiBaseUrl` | API origin
|
|
54
|
+
| `projectId` | Your project id, e.g. `436582-forms.abprojects.com`. **Required.** |
|
|
55
|
+
| `token` | The auth JWT from the login response. Required for authenticated calls. |
|
|
56
|
+
| `apiBaseUrl` | API origin, e.g. `https://partner-api.example.com`. Falls back to the `VITE_AUTH_API_BASE_URL` env var. |
|
|
57
|
+
|
|
58
|
+
You own the token: persist it (e.g. `localStorage`) on `onSuccess`, pass it back into the authenticated components/functions, and clear it on logout.
|
|
41
59
|
|
|
42
60
|
---
|
|
43
61
|
|
|
44
62
|
## Auth screens
|
|
45
63
|
|
|
46
|
-
### Login
|
|
64
|
+
### `Login`
|
|
47
65
|
|
|
48
66
|
```tsx
|
|
49
67
|
import { Login } from "ab-ecosystem-sso";
|
|
@@ -56,9 +74,9 @@ function LoginPage() {
|
|
|
56
74
|
apiBaseUrl="https://your-api"
|
|
57
75
|
onSuccess={({ token, user }) => {
|
|
58
76
|
localStorage.setItem("token", token);
|
|
59
|
-
|
|
77
|
+
navigate("/dashboard");
|
|
60
78
|
}}
|
|
61
|
-
onError={(err) =>
|
|
79
|
+
onError={(err) => toast.error(err.message)}
|
|
62
80
|
onForgotPassword={() => navigate("/forgot-password")}
|
|
63
81
|
onSignupClick={() => navigate("/signup")}
|
|
64
82
|
/>
|
|
@@ -66,33 +84,35 @@ function LoginPage() {
|
|
|
66
84
|
}
|
|
67
85
|
```
|
|
68
86
|
|
|
69
|
-
`Login` fetches the project's `auth-config` (captcha, branding, which links to show) and renders accordingly. If the account has **2FA** enabled
|
|
87
|
+
`Login` first fetches the project's `auth-config` (captcha provider/site-key, branding, which links to show) and renders accordingly. If the account has **2FA** enabled it automatically shows a **segmented 6-digit OTP** step (with captcha when the project requires it), and only calls `onSuccess` after verification succeeds.
|
|
70
88
|
|
|
71
|
-
### Signup
|
|
89
|
+
### `Signup` and `ForgotPassword`
|
|
72
90
|
|
|
73
91
|
```tsx
|
|
74
92
|
import { Signup, ForgotPassword } from "ab-ecosystem-sso";
|
|
75
93
|
|
|
76
|
-
<Signup projectId="…" onSuccess={
|
|
94
|
+
<Signup projectId="…" onSuccess={handleAuth} onLoginClick={() => navigate("/login")} />
|
|
77
95
|
<ForgotPassword projectId="…" onBackToLogin={() => navigate("/login")} />
|
|
78
96
|
```
|
|
79
97
|
|
|
80
|
-
###
|
|
98
|
+
### Shared auth props
|
|
81
99
|
|
|
82
100
|
| Prop | Type | Notes |
|
|
83
101
|
| --- | --- | --- |
|
|
84
|
-
| `projectId` | `string` | Required
|
|
102
|
+
| `projectId` | `string` | **Required.** |
|
|
85
103
|
| `apiBaseUrl` | `string` | Optional API origin. |
|
|
86
104
|
| `config` | `AuthConfig` | Pre-fetched auth-config to skip the internal request. |
|
|
87
|
-
| `onSuccess` | `({ token, user }) => void` |
|
|
88
|
-
| `onError` | `(error: Error) => void` |
|
|
89
|
-
| `classNames` | `AuthClassNames` | Per-element class overrides
|
|
105
|
+
| `onSuccess` | `({ token, user }) => void` | On successful auth. |
|
|
106
|
+
| `onError` | `(error: Error) => void` | On failure. |
|
|
107
|
+
| `classNames` | `AuthClassNames` | Per-element class overrides: `card`, `input`, `label`, `button`, `link`, `captcha`, `error`, … |
|
|
108
|
+
|
|
109
|
+
Per-screen extras: `Login` adds `onForgotPassword` / `onSignupClick`; `Signup` adds `onLoginClick`; `ForgotPassword` adds `onBackToLogin`.
|
|
90
110
|
|
|
91
111
|
---
|
|
92
112
|
|
|
93
|
-
## Session
|
|
113
|
+
## Session management
|
|
94
114
|
|
|
95
|
-
Wrap authenticated areas
|
|
115
|
+
Wrap authenticated areas in `SessionProvider`. It validates the token against `/me` and renders children only when the session is valid; otherwise it calls `onSessionInvalid` (redirect to login there).
|
|
96
116
|
|
|
97
117
|
```tsx
|
|
98
118
|
import { SessionProvider } from "ab-ecosystem-sso";
|
|
@@ -107,9 +127,17 @@ import { SessionProvider } from "ab-ecosystem-sso";
|
|
|
107
127
|
</SessionProvider>
|
|
108
128
|
```
|
|
109
129
|
|
|
130
|
+
| Prop | Type | Notes |
|
|
131
|
+
| --- | --- | --- |
|
|
132
|
+
| `projectId` | `string` | **Required.** |
|
|
133
|
+
| `token` | `string \| null` | Null ⇒ treated as signed-out. |
|
|
134
|
+
| `onSessionInvalid` | `() => void` | Called on invalid/expired session or logout. |
|
|
135
|
+
| `apiBaseUrl` | `string` | Optional. |
|
|
136
|
+
| `enforceActiveSubscription` | `boolean` | See below. |
|
|
137
|
+
|
|
110
138
|
### Enforce an active subscription
|
|
111
139
|
|
|
112
|
-
|
|
140
|
+
With `enforceActiveSubscription`, once authenticated the provider checks the user's subscription. If none is active it opens the Account Settings modal on the **Plans** section — and **blocks closing until a subscription exists** (it re-checks on every close attempt).
|
|
113
141
|
|
|
114
142
|
```tsx
|
|
115
143
|
<SessionProvider … enforceActiveSubscription>
|
|
@@ -121,7 +149,7 @@ Pass `enforceActiveSubscription` and, once authenticated, the provider checks th
|
|
|
121
149
|
|
|
122
150
|
## Account Settings modal
|
|
123
151
|
|
|
124
|
-
A
|
|
152
|
+
A complete settings surface with these sections: **General** (profile), **Account** (email, change password, 2FA, sessions), **Wallet & Balance** (balances + transaction history), **Plans & Add-ons** (subscribe, multi-subscribe add-ons, markdown plan details), and **Credit Wallets** (per-wallet balance, logs, top-up). It loads and saves via the live API whenever `projectId` + `token` are supplied (otherwise it renders sample data).
|
|
125
153
|
|
|
126
154
|
### Imperative (recommended)
|
|
127
155
|
|
|
@@ -134,14 +162,14 @@ import { openAccountSettings } from "ab-ecosystem-sso";
|
|
|
134
162
|
projectId: "your-project-id",
|
|
135
163
|
token,
|
|
136
164
|
apiBaseUrl: "https://your-api",
|
|
137
|
-
initialSection: "plans",
|
|
165
|
+
initialSection: "plans", // optional
|
|
138
166
|
onLogout: () => { localStorage.clear(); navigate("/login"); },
|
|
139
167
|
})}>
|
|
140
168
|
Settings
|
|
141
169
|
</button>
|
|
142
170
|
```
|
|
143
171
|
|
|
144
|
-
`openAccountSettings(options)` returns `{ close() }` to dismiss it programmatically.
|
|
172
|
+
`openAccountSettings(options)` returns a handle: `{ close() }` to dismiss it programmatically.
|
|
145
173
|
|
|
146
174
|
### Declarative
|
|
147
175
|
|
|
@@ -161,7 +189,25 @@ const [open, setOpen] = useState(false);
|
|
|
161
189
|
/>
|
|
162
190
|
```
|
|
163
191
|
|
|
164
|
-
|
|
192
|
+
### Props
|
|
193
|
+
|
|
194
|
+
| Prop | Type | Notes |
|
|
195
|
+
| --- | --- | --- |
|
|
196
|
+
| `open` | `boolean` | **Required** (declarative). |
|
|
197
|
+
| `onOpenChange` | `(open: boolean) => void` | **Required** (declarative). |
|
|
198
|
+
| `projectId` | `string` | Enables live API mode (with `token`). |
|
|
199
|
+
| `token` | `string` | Bearer token. |
|
|
200
|
+
| `apiBaseUrl` | `string` | Optional API origin. |
|
|
201
|
+
| `initialSection` | `"general" \| "account" \| "wallet" \| "plans" \| "credits"` | First section shown. Default `"general"`. |
|
|
202
|
+
| `title` | `string` | Modal heading. Default `"Settings"`. |
|
|
203
|
+
| `data` | `Partial<AccountSettingsData>` | Override sample data (non-API mode / previews). |
|
|
204
|
+
| `onLogout` | `() => void` | Sign-out action (closes the modal, then runs this). |
|
|
205
|
+
| `onSaveProfile` | `(profile) => void` | Fires alongside the profile save. |
|
|
206
|
+
| `onChangePassword` | `(data) => void` | Fires alongside the password change. |
|
|
207
|
+
| `onChangePlan` | `(planId) => void` | Fires when a plan is subscribed. |
|
|
208
|
+
| `onUpdateWhatsApp`, `onToggleTwoFactor`, `onRevokeSession`, `onAddFunds` | callbacks | Observers for the respective actions. |
|
|
209
|
+
|
|
210
|
+
> In live mode the modal performs the API calls itself (save profile, change password, subscribe, recharge, etc.); the callbacks are observation hooks, not required wiring.
|
|
165
211
|
|
|
166
212
|
---
|
|
167
213
|
|
|
@@ -172,7 +218,7 @@ Three options, from most convenient to most raw:
|
|
|
172
218
|
```tsx
|
|
173
219
|
import { LogoutButton, logout, logoutApi } from "ab-ecosystem-sso";
|
|
174
220
|
|
|
175
|
-
// 1) Ready-made button (no SessionProvider needed
|
|
221
|
+
// 1) Ready-made button (works standalone, no SessionProvider needed)
|
|
176
222
|
<LogoutButton
|
|
177
223
|
projectId="your-project-id"
|
|
178
224
|
token={token}
|
|
@@ -186,30 +232,63 @@ onClick={() => logout({
|
|
|
186
232
|
token,
|
|
187
233
|
apiBaseUrl: "https://your-api",
|
|
188
234
|
onSuccess: () => { localStorage.clear(); navigate("/login"); },
|
|
235
|
+
onError: (e) => console.error(e),
|
|
189
236
|
})}
|
|
190
237
|
|
|
191
238
|
// 3) The raw endpoint call
|
|
192
239
|
await logoutApi("your-project-id", token, "https://your-api");
|
|
193
240
|
```
|
|
194
241
|
|
|
195
|
-
`logout` POSTs to `/auth/logout` and always runs `onSuccess` once the request settles — so the user is logged out client-side even if the server call fails (`onError` fires for observability). Inside a `SessionProvider`, `<LogoutButton />`
|
|
242
|
+
`logout` POSTs to `/auth/logout` and **always runs `onSuccess` once the request settles** — so the user is logged out client-side even if the server call fails (`onError` fires for observability). Inside a `SessionProvider`, `<LogoutButton />` with no props uses the provider's logout instead.
|
|
196
243
|
|
|
197
244
|
---
|
|
198
245
|
|
|
199
|
-
##
|
|
246
|
+
## Fetching the current user
|
|
200
247
|
|
|
201
|
-
Populate your own header/profile-dropdown from `/me`:
|
|
248
|
+
Populate your own header / profile-dropdown from `/me`:
|
|
202
249
|
|
|
203
250
|
```tsx
|
|
204
251
|
import { getUser } from "ab-ecosystem-sso";
|
|
205
252
|
|
|
206
253
|
const res = await getUser("your-project-id", token, "https://your-api");
|
|
207
|
-
|
|
254
|
+
// res = { success, data: { id, username, profile: { name, email, address, … }, mainWallet, coinWallet } }
|
|
255
|
+
const firstName = res.data.profile.name.first;
|
|
208
256
|
```
|
|
209
257
|
|
|
258
|
+
`getUser` returns the raw response envelope and throws `AuthApiError` on a non-2xx response.
|
|
259
|
+
|
|
210
260
|
---
|
|
211
261
|
|
|
212
|
-
##
|
|
262
|
+
## Fetching user data
|
|
263
|
+
|
|
264
|
+
When you want clean, ready-to-render data instead of the raw envelope, use these getters. Each **fetches and maps** in one call, and all share the same `(projectId, token, apiBaseUrl?)` signature.
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
import {
|
|
268
|
+
getUserProfile,
|
|
269
|
+
getUserWallet,
|
|
270
|
+
getUserCreditWallet,
|
|
271
|
+
getUserSubscription,
|
|
272
|
+
} from "ab-ecosystem-sso";
|
|
273
|
+
|
|
274
|
+
const profile = await getUserProfile("your-project-id", token, "https://your-api");
|
|
275
|
+
const { mainWallet, coinWallet } = await getUserWallet("your-project-id", token, "https://your-api");
|
|
276
|
+
const creditWallets = await getUserCreditWallet("your-project-id", token, "https://your-api");
|
|
277
|
+
const subscription = await getUserSubscription("your-project-id", token, "https://your-api");
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
| Function | Endpoint | Returns |
|
|
281
|
+
| --- | --- | --- |
|
|
282
|
+
| `getUserProfile` | `GET /me` | `MappedProfile` — flat fields (name, `email`/`username`, address, phone, `mainWallet`/`coinWallet`). |
|
|
283
|
+
| `getUserWallet` | `GET /me` | `UserWallets` — just `{ mainWallet, coinWallet }` balances. |
|
|
284
|
+
| `getUserCreditWallet` | `GET /credit-wallets` | `CreditWallet[]` — each `{ id, label, balance, balanceFormatted, creditUnit, fundSource, rechargeable }`. |
|
|
285
|
+
| `getUserSubscription` | `GET /subscription` | `MappedSubscription` — `planId` (empty if none), `status`, `renewsAt`, `subscribedIds`, `packageCounts`. |
|
|
286
|
+
|
|
287
|
+
> `getUserProfile` and `getUserWallet` both read `/me`; `getUserWallet` just narrows the same response to the wallet balances. All four throw `AccountApiError` on a non-2xx response.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
## Two-factor setup
|
|
213
292
|
|
|
214
293
|
For a settings page outside the modal:
|
|
215
294
|
|
|
@@ -222,6 +301,7 @@ import { TwoFactorSetup } from "ab-ecosystem-sso";
|
|
|
222
301
|
apiBaseUrl="https://your-api"
|
|
223
302
|
onEnabled={() => …}
|
|
224
303
|
onDisabled={() => …}
|
|
304
|
+
onError={(err) => …}
|
|
225
305
|
/>
|
|
226
306
|
```
|
|
227
307
|
|
|
@@ -239,22 +319,40 @@ import { TwoFactorSetup } from "ab-ecosystem-sso";
|
|
|
239
319
|
|
|
240
320
|
## Theming
|
|
241
321
|
|
|
242
|
-
The UI reads CSS custom properties
|
|
322
|
+
The UI reads `--aas-*` CSS custom properties, so you can retheme without touching the components. Override them on `:root` (or any ancestor) after importing the stylesheet:
|
|
243
323
|
|
|
244
324
|
```css
|
|
245
325
|
:root {
|
|
246
|
-
--aas-primary:
|
|
247
|
-
--aas-primary-foreground:
|
|
248
|
-
--aas-background:
|
|
249
|
-
--aas-foreground:
|
|
250
|
-
--aas-muted:
|
|
251
|
-
--aas-muted-foreground:
|
|
252
|
-
--aas-border:
|
|
253
|
-
--aas-radius: 0.
|
|
326
|
+
--aas-primary: oklch(0.55 0.22 265);
|
|
327
|
+
--aas-primary-foreground: oklch(0.99 0 0);
|
|
328
|
+
--aas-background: oklch(1 0 0);
|
|
329
|
+
--aas-foreground: oklch(0.15 0 0);
|
|
330
|
+
--aas-muted: oklch(0.97 0 0);
|
|
331
|
+
--aas-muted-foreground: oklch(0.55 0 0);
|
|
332
|
+
--aas-border: oklch(0.92 0 0);
|
|
333
|
+
--aas-radius: 0.625rem;
|
|
254
334
|
}
|
|
255
335
|
```
|
|
256
336
|
|
|
257
|
-
|
|
337
|
+
The styles are theme-aware and scoped to the components — they won't affect the rest of your app, and your app's global resets can't override them.
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## API reference
|
|
342
|
+
|
|
343
|
+
Beyond the components, these functions are exported for building custom UIs:
|
|
344
|
+
|
|
345
|
+
| Function | Endpoint |
|
|
346
|
+
| --- | --- |
|
|
347
|
+
| `getUser(projectId, token, apiBaseUrl?)` | `GET /me` (raw envelope) |
|
|
348
|
+
| `getUserProfile(projectId, token, apiBaseUrl?)` | `GET /me` → `MappedProfile` |
|
|
349
|
+
| `getUserWallet(projectId, token, apiBaseUrl?)` | `GET /me` → `UserWallets` |
|
|
350
|
+
| `getUserCreditWallet(projectId, token, apiBaseUrl?)` | `GET /credit-wallets` → `CreditWallet[]` |
|
|
351
|
+
| `getUserSubscription(projectId, token, apiBaseUrl?)` | `GET /subscription` → `MappedSubscription` |
|
|
352
|
+
| `logout(options)` | `POST /auth/logout` + callbacks |
|
|
353
|
+
| `logoutApi(projectId, token, apiBaseUrl?)` | `POST /auth/logout` |
|
|
354
|
+
|
|
355
|
+
> The Account Settings modal also drives a wider set of endpoints internally — profile (`/me`, `/profile`), password (`/account`), 2FA, WhatsApp, plans/subscription (`/plans`, `/subscribe`, `/subscription`), wallet (`/wallet/logs`, `/recharge-links`), and credit wallets (`/credit-wallets`, `/credit-wallets/:id/logs`, `/credit-wallets/:id/recharge`). If you need any of these as standalone helpers, open an issue and they can be exported.
|
|
258
356
|
|
|
259
357
|
---
|
|
260
358
|
|
|
@@ -265,11 +363,13 @@ Everything is fully typed. Notable exports:
|
|
|
265
363
|
```ts
|
|
266
364
|
import type {
|
|
267
365
|
LoginProps, SignupProps, ForgotPasswordProps, AuthClassNames,
|
|
268
|
-
AccountSettingsProps, AccountSettingsSection,
|
|
366
|
+
AccountSettingsProps, AccountSettingsSection, AccountSettingsData, ProfileFormValues,
|
|
269
367
|
OpenAccountSettingsOptions, AccountSettingsHandle,
|
|
270
368
|
AuthConfig, CaptchaConfig, CardLayoutConfig,
|
|
271
|
-
LoginRequest, AuthResponse, LogoutOptions,
|
|
369
|
+
LoginRequest, SignupRequest, ForgotPasswordRequest, AuthResponse, LogoutOptions,
|
|
370
|
+
MappedProfile, WalletInfo, UserWallets, CreditWallet, MappedSubscription,
|
|
272
371
|
} from "ab-ecosystem-sso";
|
|
372
|
+
|
|
273
373
|
import { AuthApiError } from "ab-ecosystem-sso";
|
|
274
374
|
```
|
|
275
375
|
|