@s8lab/sso-client 1.0.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 ADDED
@@ -0,0 +1,193 @@
1
+ # @s8lab/sso-client
2
+
3
+ React authentication component library — **Login**, **Signup**, **Forgot Password**, **Logout**, and **Profile** — with Google reCAPTCHA v2 and shadcn-style UI built on Radix UI + Tailwind CSS.
4
+
5
+ ---
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ npm install @s8lab/sso-client
11
+ ```
12
+
13
+ > **Peer dependencies** — make sure your project has `react` and `react-dom` ≥ 18.
14
+
15
+ ### Tailwind setup (required)
16
+
17
+ Add this library to your Tailwind `content` so its classes are picked up:
18
+
19
+ ```js
20
+ // tailwind.config.js
21
+ export default {
22
+ content: [
23
+ "./src/**/*.{ts,tsx}",
24
+ "./node_modules/@s8lab/sso-client/dist/**/*.js",
25
+ ],
26
+ // ...
27
+ };
28
+ ```
29
+
30
+ Then import the bundled CSS once at your app root:
31
+
32
+ ```ts
33
+ import "@s8lab/sso-client/styles.css";
34
+ ```
35
+
36
+ ---
37
+
38
+ ## Quick start
39
+
40
+ ### 1 — Wrap your app with `<AuthProvider>`
41
+
42
+ ```tsx
43
+ import { AuthProvider } from "@s8lab/sso-client";
44
+
45
+ function App() {
46
+ return (
47
+ <AuthProvider
48
+ apiUrl="https://api.yourapp.com"
49
+ recaptchaSiteKey="6LeXXXXXXXXXXXXXXXXX"
50
+ >
51
+ <Router />
52
+ </AuthProvider>
53
+ );
54
+ }
55
+ ```
56
+
57
+ #### `AuthProvider` props
58
+
59
+ | Prop | Type | Default | Description |
60
+ |---|---|---|---|
61
+ | `apiUrl` | `string` | **required** | Base URL of your SSO server |
62
+ | `recaptchaSiteKey` | `string` | **required** | Google reCAPTCHA v2 site key |
63
+ | `storageKeyPrefix` | `string` | `"sso"` | localStorage key prefix for tokens |
64
+ | `fetcher` | `(url, init) => Promise<T>` | built-in fetch | Override for custom headers/interceptors |
65
+
66
+ ---
67
+
68
+ ### 2 — Use the components
69
+
70
+ ```tsx
71
+ import {
72
+ LoginForm,
73
+ SignupForm,
74
+ ForgotPasswordForm,
75
+ LogoutButton,
76
+ ProfileComponent,
77
+ } from "@s8lab/sso-client";
78
+ ```
79
+
80
+ #### `<LoginForm>`
81
+
82
+ ```tsx
83
+ <LoginForm
84
+ className="mx-auto"
85
+ title="Welcome back"
86
+ description="Sign in to your account"
87
+ signupUrl="/signup"
88
+ forgotPasswordUrl="/forgot-password"
89
+ onSuccess={(user) => router.push("/dashboard")}
90
+ onError={(err) => toast.error(err.message)}
91
+ />
92
+ ```
93
+
94
+ #### `<SignupForm>`
95
+
96
+ ```tsx
97
+ <SignupForm
98
+ className="mx-auto"
99
+ loginUrl="/login"
100
+ onSuccess={(user) => router.push("/dashboard")}
101
+ />
102
+ ```
103
+
104
+ #### `<ForgotPasswordForm>`
105
+
106
+ ```tsx
107
+ <ForgotPasswordForm
108
+ loginUrl="/login"
109
+ onSuccess={() => toast.success("Reset link sent!")}
110
+ />
111
+ ```
112
+
113
+ #### `<LogoutButton>`
114
+
115
+ ```tsx
116
+ // Default button
117
+ <LogoutButton onSuccess={() => router.push("/login")} />
118
+
119
+ // Custom render
120
+ <LogoutButton onSuccess={() => router.push("/login")}>
121
+ {({ isLoading }) => (
122
+ <button disabled={isLoading}>
123
+ {isLoading ? "Logging out…" : "Log out"}
124
+ </button>
125
+ )}
126
+ </LogoutButton>
127
+ ```
128
+
129
+ #### `<ProfileComponent>`
130
+
131
+ ```tsx
132
+ <ProfileComponent
133
+ showLogout
134
+ onLogoutSuccess={() => router.push("/login")}
135
+ onEditProfile={(user) => router.push("/settings")}
136
+ />
137
+ ```
138
+
139
+ ---
140
+
141
+ ### 3 — `useAuth` hook
142
+
143
+ Access auth state and actions anywhere inside `<AuthProvider>`:
144
+
145
+ ```tsx
146
+ import { useAuth } from "@s8lab/sso-client";
147
+
148
+ function Dashboard() {
149
+ const { user, isAuthenticated, isLoading, logout } = useAuth();
150
+
151
+ if (isLoading) return <Spinner />;
152
+ if (!isAuthenticated) return <Redirect to="/login" />;
153
+
154
+ return <h1>Hello, {user.firstName}!</h1>;
155
+ }
156
+ ```
157
+
158
+ ---
159
+
160
+ ## API server contract
161
+
162
+ The `AuthProvider` expects the following endpoints on your `apiUrl`:
163
+
164
+ | Method | Path | Request body | Response |
165
+ |---|---|---|---|
166
+ | `POST` | `/auth/login` | `{ email, password, recaptchaToken }` | `{ user, tokens }` |
167
+ | `POST` | `/auth/signup` | `{ firstName, lastName, email, password, whatsappNumber?, recaptchaToken }` | `{ user, tokens }` |
168
+ | `POST` | `/auth/logout` | *(none)* | `204` |
169
+ | `POST` | `/auth/forgot-password` | `{ email, recaptchaToken }` | `200` |
170
+ | `GET` | `/auth/me` | *(Authorization header)* | `User` |
171
+
172
+ `tokens` shape: `{ accessToken: string; refreshToken?: string }`
173
+
174
+ ---
175
+
176
+ ## Customising styles
177
+
178
+ Every component accepts a `className` prop that is merged onto the outer `Card` via `tailwind-merge`, so you can freely override any Tailwind class:
179
+
180
+ ```tsx
181
+ <LoginForm className="border-2 border-indigo-500 shadow-xl rounded-2xl" />
182
+ ```
183
+
184
+ CSS variables for the design tokens (colors, radius, etc.) follow the standard shadcn/ui convention and can be overridden globally in your CSS.
185
+
186
+ ---
187
+
188
+ ## Publishing to npm
189
+
190
+ ```bash
191
+ npm run build
192
+ npm publish --access public
193
+ ```
@@ -0,0 +1,20 @@
1
+ import { CaptchaConfig } from '../types';
2
+ export interface CaptchaHandle {
3
+ reset: () => void;
4
+ }
5
+ interface CaptchaWidgetProps {
6
+ config: CaptchaConfig;
7
+ onVerify: (token: string) => void;
8
+ onExpire: () => void;
9
+ }
10
+ /**
11
+ * Renders the appropriate captcha widget based on config:
12
+ * - recaptcha v2 → Google checkbox widget
13
+ * - hcaptcha → hCaptcha checkbox widget
14
+ * - recaptcha v3 → nothing (invisible; execute via executeRecaptchaV3 util)
15
+ * - disabled → nothing
16
+ *
17
+ * Expose .reset() via ref to reset the widget after submission.
18
+ */
19
+ export declare const CaptchaWidget: import('react').ForwardRefExoticComponent<CaptchaWidgetProps & import('react').RefAttributes<CaptchaHandle>>;
20
+ export {};
@@ -0,0 +1,2 @@
1
+ import { ForgotPasswordFormProps } from '../types';
2
+ export declare function ForgotPasswordForm({ className, onSuccess, onError, loginUrl, title, }: ForgotPasswordFormProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { LoginFormProps } from '../types';
2
+ export declare function LoginForm({ className, onSuccess, onError, forgotPasswordUrl, signupUrl, title, }: LoginFormProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { LogoutButtonProps } from '../types';
2
+ export declare function LogoutButton({ className, onSuccess, onError, label, children, }: LogoutButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { ProfileComponentProps } from '../types';
2
+ export declare function ProfileComponent({ className, onEditProfile, showLogout, onLogoutSuccess, }: ProfileComponentProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ import { SignupFormProps } from '../types';
2
+ export declare function SignupForm({ className, onSuccess, onError, loginUrl, title, }: SignupFormProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import * as React from "react";
2
+ import * as AvatarPrimitive from "@radix-ui/react-avatar";
3
+ declare const Avatar: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
4
+ declare const AvatarImage: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarImageProps & React.RefAttributes<HTMLImageElement>, "ref"> & React.RefAttributes<HTMLImageElement>>;
5
+ declare const AvatarFallback: React.ForwardRefExoticComponent<Omit<AvatarPrimitive.AvatarFallbackProps & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
6
+ export { Avatar, AvatarImage, AvatarFallback };
@@ -0,0 +1,11 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ import * as React from "react";
3
+ declare const buttonVariants: (props?: ({
4
+ variant?: "link" | "default" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined;
5
+ size?: "default" | "sm" | "lg" | "icon" | null | undefined;
6
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
7
+ export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof buttonVariants> {
8
+ asChild?: boolean;
9
+ }
10
+ declare const Button: React.ForwardRefExoticComponent<ButtonProps & React.RefAttributes<HTMLButtonElement>>;
11
+ export { Button, buttonVariants };
@@ -0,0 +1,8 @@
1
+ import * as React from "react";
2
+ declare const Card: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
3
+ declare const CardHeader: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
4
+ declare const CardTitle: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLHeadingElement> & React.RefAttributes<HTMLParagraphElement>>;
5
+ declare const CardDescription: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLParagraphElement> & React.RefAttributes<HTMLParagraphElement>>;
6
+ declare const CardContent: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
7
+ declare const CardFooter: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLDivElement> & React.RefAttributes<HTMLDivElement>>;
8
+ export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent };
@@ -0,0 +1,4 @@
1
+ import * as React from "react";
2
+ import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3
+ declare const Checkbox: React.ForwardRefExoticComponent<Omit<CheckboxPrimitive.CheckboxProps & React.RefAttributes<HTMLButtonElement>, "ref"> & React.RefAttributes<HTMLButtonElement>>;
4
+ export { Checkbox };
@@ -0,0 +1,5 @@
1
+ import * as React from "react";
2
+ export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
3
+ }
4
+ declare const Input: React.ForwardRefExoticComponent<InputProps & React.RefAttributes<HTMLInputElement>>;
5
+ export { Input };
@@ -0,0 +1,5 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ import * as React from "react";
3
+ import * as LabelPrimitive from "@radix-ui/react-label";
4
+ declare const Label: React.ForwardRefExoticComponent<Omit<LabelPrimitive.LabelProps & React.RefAttributes<HTMLLabelElement>, "ref"> & VariantProps<(props?: import('class-variance-authority/types').ClassProp | undefined) => string> & React.RefAttributes<HTMLLabelElement>>;
5
+ export { Label };
@@ -0,0 +1,4 @@
1
+ import * as React from "react";
2
+ import * as SeparatorPrimitive from "@radix-ui/react-separator";
3
+ declare const Separator: React.ForwardRefExoticComponent<Omit<SeparatorPrimitive.SeparatorProps & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
4
+ export { Separator };
@@ -0,0 +1,4 @@
1
+ import { AuthConfigContextValue, AuthContextValue, AuthProviderProps } from '../types';
2
+ export declare function AuthProvider({ children, apiUrl, projectId, storageKeyPrefix, fetcher, }: AuthProviderProps): import("react/jsx-runtime").JSX.Element;
3
+ export declare function useAuth(): AuthContextValue;
4
+ export declare function useAuthConfig(): AuthConfigContextValue;