@instroc/auth 1.0.2 → 1.1.1

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.
@@ -0,0 +1 @@
1
+ export { M as MessageOverrides, O as OnErrorResult, m as UseForgotPasswordFormOptions, n as UseForgotPasswordFormReturn, U as UseLoginFormOptions, h as UseLoginFormReturn, k as UseOtpFormOptions, l as UseOtpFormReturn, o as UseResetPasswordFormOptions, p as UseResetPasswordFormReturn, i as UseSignupFormOptions, j as UseSignupFormReturn, f as useForgotPasswordForm, u as useLoginForm, e as useOtpForm, g as useResetPasswordForm, d as useSignupForm } from './index-D4rCSC9H.js';
package/dist/forms.js ADDED
@@ -0,0 +1,14 @@
1
+ import {
2
+ useForgotPasswordForm,
3
+ useLoginForm,
4
+ useOtpForm,
5
+ useResetPasswordForm,
6
+ useSignupForm
7
+ } from "./chunk-T7NGX4DQ.js";
8
+ export {
9
+ useForgotPasswordForm,
10
+ useLoginForm,
11
+ useOtpForm,
12
+ useResetPasswordForm,
13
+ useSignupForm
14
+ };
@@ -0,0 +1,365 @@
1
+ interface AuthUser {
2
+ id: string;
3
+ email: string;
4
+ email_verified: boolean;
5
+ display_name: string | null;
6
+ avatar_url: string | null;
7
+ metadata: Record<string, unknown>;
8
+ created_at: string;
9
+ }
10
+ interface AuthSession {
11
+ access_token: string;
12
+ refresh_token: string;
13
+ expires_at: string;
14
+ }
15
+ interface AuthState {
16
+ user: AuthUser | null;
17
+ session: AuthSession | null;
18
+ loading: boolean;
19
+ error: string | null;
20
+ }
21
+ interface LoginCredentials {
22
+ email: string;
23
+ password: string;
24
+ }
25
+ interface SignupCredentials {
26
+ email: string;
27
+ password: string;
28
+ displayName?: string;
29
+ metadata?: Record<string, unknown>;
30
+ }
31
+ type OAuthProvider = "google" | "github" | "microsoft" | "facebook";
32
+ interface AuthConfig {
33
+ emailAuthEnabled: boolean;
34
+ googleAuthEnabled: boolean;
35
+ githubAuthEnabled: boolean;
36
+ microsoftAuthEnabled: boolean;
37
+ facebookAuthEnabled: boolean;
38
+ allowSignup: boolean;
39
+ requireEmailVerification: boolean;
40
+ }
41
+ interface VisibilityConfig {
42
+ projectName: string;
43
+ visibility: "public" | "private";
44
+ requireLogin: boolean;
45
+ logoUrl: string | null;
46
+ welcomeMessage: string | null;
47
+ }
48
+ /**
49
+ * Result of signup() — indicates what post-signup flow the caller should show.
50
+ *
51
+ * - `status: "authenticated"` — user is logged in, session is active. Redirect to app.
52
+ * - `status: "needs_verification"` — email verification OTP was sent. Show OTP screen.
53
+ * - `status: "needs_approval"` — account pending admin approval. Show waiting screen.
54
+ */
55
+ type SignupResult = {
56
+ status: "authenticated";
57
+ user: AuthUser;
58
+ } | {
59
+ status: "needs_verification";
60
+ email: string;
61
+ } | {
62
+ status: "needs_approval";
63
+ user: AuthUser;
64
+ };
65
+ interface AuthContextValue extends AuthState {
66
+ login: (credentials: LoginCredentials) => Promise<void>;
67
+ signup: (credentials: SignupCredentials) => Promise<SignupResult>;
68
+ logout: () => Promise<void>;
69
+ signInWithOAuth: (provider: OAuthProvider) => void;
70
+ verifyOTP: (email: string, code: string) => Promise<void>;
71
+ resendOTP: (email: string) => Promise<void>;
72
+ updateProfile: (data: UpdateProfileData) => Promise<void>;
73
+ refreshSession: () => Promise<void>;
74
+ forgotPassword: (email: string) => Promise<void>;
75
+ resetPassword: (token: string, newPassword: string) => Promise<void>;
76
+ setProjectId: (projectId: string) => void;
77
+ projectId: string | null;
78
+ authConfig: AuthConfig | null;
79
+ visibilityConfig: VisibilityConfig | null;
80
+ }
81
+ interface UpdateProfileData {
82
+ displayName?: string;
83
+ avatarUrl?: string;
84
+ metadata?: Record<string, unknown>;
85
+ }
86
+ interface AuthProviderProps {
87
+ children: React.ReactNode;
88
+ projectId?: string;
89
+ baseUrl?: string;
90
+ persistSession?: boolean;
91
+ onAuthStateChange?: (user: AuthUser | null) => void;
92
+ }
93
+ interface AuthResponse {
94
+ user: AuthUser;
95
+ session: AuthSession;
96
+ /** Set when signup requires email verification — session is a placeholder with empty tokens. */
97
+ needsVerification?: boolean;
98
+ /** Set when signup succeeded but account is pending admin approval (private apps). */
99
+ needsApproval?: boolean;
100
+ }
101
+ interface RefreshResponse {
102
+ access_token: string;
103
+ expires_at: string;
104
+ }
105
+
106
+ /**
107
+ * Optional override map: for a given HTTP status, display this message instead
108
+ * of the server's `error` string. The AI uses this to customize copy per app
109
+ * (e.g. `{ 429: "Whoa, slow down." }`).
110
+ */
111
+ type MessageOverrides = Partial<Record<number, string>>;
112
+ /**
113
+ * Return type for `onError` callbacks across form hooks. Controls what message
114
+ * (if any) gets set on the form's `error` state:
115
+ *
116
+ * - `string` → use this as the error message (overrides defaults)
117
+ * - `null` → suppress entirely; no error banner shown
118
+ * - `undefined`/void → fall through to the default `resolveErrorMessage` logic
119
+ *
120
+ * This is the main extension point for custom flows — e.g. reading `err.code`
121
+ * to produce tailored copy, or suppressing the banner while handling the error
122
+ * with a different UI surface (a toast, a redirect, a modal).
123
+ */
124
+ type OnErrorResult = string | null | void;
125
+
126
+ interface UseLoginFormOptions {
127
+ /** Called after a successful login — typically `() => navigate("/")`. */
128
+ onSuccess?: (user: AuthUser) => void;
129
+ /**
130
+ * Called when the server returns 403 (`email_not_verified`). Typically
131
+ * `(email) => navigate("/verify-email", { state: { email } })`. When this
132
+ * callback is provided, the 403 is treated as a routing signal, not an
133
+ * error — `error` state is NOT set.
134
+ */
135
+ onNeedsVerification?: (email: string) => void;
136
+ /**
137
+ * Customize error handling. Receives the raw thrown value — inspect
138
+ * `err instanceof AuthError`, `err.status`, or `err.code` to branch.
139
+ *
140
+ * Return value controls the form's `error` state:
141
+ * - `string` → use this as the error message
142
+ * - `null` → suppress (no error banner)
143
+ * - `void` → fall through to the default message
144
+ */
145
+ onError?: (err: unknown) => OnErrorResult;
146
+ /** Override user-facing copy by HTTP status. Keys are status codes. */
147
+ messages?: MessageOverrides;
148
+ }
149
+ interface UseLoginFormReturn {
150
+ submit: (credentials: LoginCredentials) => Promise<void>;
151
+ loading: boolean;
152
+ /** User-facing message, or null. Always a string — never an Error object. */
153
+ error: string | null;
154
+ /** Imperatively set the error message (e.g. for custom pre-submit validation). */
155
+ setError: (message: string | null) => void;
156
+ clearError: () => void;
157
+ }
158
+ /**
159
+ * Headless login form hook. Eliminates the handleSubmit + try/catch boilerplate
160
+ * that every auth page would otherwise reinvent.
161
+ *
162
+ * Usage:
163
+ * const navigate = useNavigate();
164
+ * const { submit, loading, error } = useLoginForm({
165
+ * onSuccess: () => navigate("/"),
166
+ * onNeedsVerification: (email) =>
167
+ * navigate("/verify-email", { state: { email } }),
168
+ * });
169
+ *
170
+ * <form onSubmit={(e) => { e.preventDefault(); submit({ email, password }); }}>
171
+ * …
172
+ * {error && <p className="text-red-600">{error}</p>}
173
+ * <button disabled={loading}>{loading ? "Signing in…" : "Sign in"}</button>
174
+ * </form>
175
+ *
176
+ * For custom flows — e.g. showing a 15-minute cooldown on `account_locked` —
177
+ * pass `onError` and inspect `err.code`:
178
+ *
179
+ * onError: (err) => {
180
+ * if (err instanceof AuthError && err.code === "account_locked") {
181
+ * return "Too many attempts. Try again in 15 minutes.";
182
+ * }
183
+ * }
184
+ */
185
+ declare function useLoginForm(options?: UseLoginFormOptions): UseLoginFormReturn;
186
+
187
+ interface UseSignupFormOptions {
188
+ /** Called when signup completes and the user is fully authenticated. */
189
+ onSuccess?: (user: AuthUser) => void;
190
+ /**
191
+ * Called when the server sent a verification OTP. Typically
192
+ * `(email) => navigate("/verify-email", { state: { email } })`.
193
+ *
194
+ * `needs_verification` is a SUCCESS state, NOT an error — do not route it
195
+ * through the error banner.
196
+ */
197
+ onNeedsVerification?: (email: string) => void;
198
+ /**
199
+ * Called when the account is pending admin approval (private projects).
200
+ * Typically `(user) => navigate("/pending-approval")`.
201
+ *
202
+ * `needs_approval` is a SUCCESS state, NOT an error.
203
+ */
204
+ onNeedsApproval?: (user: AuthUser) => void;
205
+ /**
206
+ * Customize error handling — see useLoginForm.onError for the return
207
+ * contract (`string` overrides, `null` suppresses, `void` defaults).
208
+ */
209
+ onError?: (err: unknown) => OnErrorResult;
210
+ /** Override user-facing copy by HTTP status. */
211
+ messages?: MessageOverrides;
212
+ }
213
+ interface UseSignupFormReturn {
214
+ submit: (credentials: SignupCredentials) => Promise<void>;
215
+ loading: boolean;
216
+ error: string | null;
217
+ setError: (message: string | null) => void;
218
+ clearError: () => void;
219
+ }
220
+ /**
221
+ * Headless signup form hook.
222
+ *
223
+ * The `SignupResult` routing (`authenticated` | `needs_verification` |
224
+ * `needs_approval`) is handled internally — callers wire each outcome to its
225
+ * own callback. None of the success states touch `error` state.
226
+ *
227
+ * Usage:
228
+ * const navigate = useNavigate();
229
+ * const { submit, loading, error } = useSignupForm({
230
+ * onSuccess: () => navigate("/"),
231
+ * onNeedsVerification: (email) =>
232
+ * navigate("/verify-email", { state: { email } }),
233
+ * onNeedsApproval: () => navigate("/pending-approval"),
234
+ * });
235
+ */
236
+ declare function useSignupForm(options?: UseSignupFormOptions): UseSignupFormReturn;
237
+
238
+ interface UseOtpFormOptions {
239
+ /** The email that the OTP was sent to. Required — typically from route state. */
240
+ email: string;
241
+ /** Called after `verifyOTP` succeeds and the user is authenticated. */
242
+ onSuccess?: () => void;
243
+ /** Called after `resendOTP` succeeds. Typically used to show a toast. */
244
+ onResendSuccess?: () => void;
245
+ /** Error customization contract — see useLoginForm.onError. */
246
+ onError?: (err: unknown) => OnErrorResult;
247
+ /** Override user-facing copy by HTTP status. */
248
+ messages?: MessageOverrides;
249
+ /** Cooldown seconds between resend attempts. Defaults to 60. */
250
+ resendCooldownSeconds?: number;
251
+ }
252
+ interface UseOtpFormReturn {
253
+ /** Verify the OTP code. */
254
+ submit: (code: string) => Promise<void>;
255
+ /** Ask the server to re-send the OTP. Respects `resendCooldownSeconds`. */
256
+ resend: () => Promise<void>;
257
+ loading: boolean;
258
+ resending: boolean;
259
+ /** Seconds remaining until the user can resend again (0 when ready). */
260
+ resendCooldown: number;
261
+ error: string | null;
262
+ setError: (message: string | null) => void;
263
+ clearError: () => void;
264
+ }
265
+ /**
266
+ * Headless OTP verification form hook. Handles both verify and resend, with
267
+ * a cooldown timer to prevent 429s.
268
+ *
269
+ * Usage:
270
+ * const navigate = useNavigate();
271
+ * const location = useLocation();
272
+ * const email = location.state?.email as string;
273
+ * const { submit, resend, loading, resendCooldown, error } = useOtpForm({
274
+ * email,
275
+ * onSuccess: () => navigate("/"),
276
+ * });
277
+ *
278
+ * <form onSubmit={(e) => { e.preventDefault(); submit(code); }}>
279
+ * …
280
+ * <button type="button" disabled={resendCooldown > 0} onClick={resend}>
281
+ * {resendCooldown > 0 ? `Resend (${resendCooldown}s)` : "Resend code"}
282
+ * </button>
283
+ * </form>
284
+ */
285
+ declare function useOtpForm(options: UseOtpFormOptions): UseOtpFormReturn;
286
+
287
+ interface UseForgotPasswordFormOptions {
288
+ /**
289
+ * Called after the server accepts the request. This fires for both "email
290
+ * exists, we sent a link" and "email doesn't exist, we silently succeeded"
291
+ * — don't tell the user which (account-enumeration leak). Typically used
292
+ * to show a "Check your email" confirmation screen.
293
+ */
294
+ onSuccess?: (email: string) => void;
295
+ onError?: (err: unknown) => OnErrorResult;
296
+ messages?: MessageOverrides;
297
+ }
298
+ interface UseForgotPasswordFormReturn {
299
+ submit: (email: string) => Promise<void>;
300
+ loading: boolean;
301
+ /** Once true, the request completed — show the "check your email" UI. */
302
+ submitted: boolean;
303
+ error: string | null;
304
+ setError: (message: string | null) => void;
305
+ clearError: () => void;
306
+ /** Reset `submitted` back to false (e.g. if the user wants to try another email). */
307
+ reset: () => void;
308
+ }
309
+ /**
310
+ * Headless forgot-password form hook.
311
+ *
312
+ * Usage:
313
+ * const { submit, loading, error, submitted } = useForgotPasswordForm();
314
+ *
315
+ * if (submitted) {
316
+ * return <p>Check your email for a reset link.</p>;
317
+ * }
318
+ *
319
+ * <form onSubmit={(e) => { e.preventDefault(); submit(email); }}>
320
+ * …
321
+ * </form>
322
+ */
323
+ declare function useForgotPasswordForm(options?: UseForgotPasswordFormOptions): UseForgotPasswordFormReturn;
324
+
325
+ interface UseResetPasswordFormOptions {
326
+ /**
327
+ * The reset token from the URL (e.g. `useSearchParams().get("token")`).
328
+ * Required — the hook does not read `window.location` to stay router-agnostic.
329
+ */
330
+ token: string;
331
+ /**
332
+ * Called after the password is successfully reset. Typically
333
+ * `() => navigate("/login")`.
334
+ */
335
+ onSuccess?: () => void;
336
+ onError?: (err: unknown) => OnErrorResult;
337
+ messages?: MessageOverrides;
338
+ }
339
+ interface UseResetPasswordFormReturn {
340
+ submit: (newPassword: string) => Promise<void>;
341
+ loading: boolean;
342
+ error: string | null;
343
+ setError: (message: string | null) => void;
344
+ clearError: () => void;
345
+ }
346
+ /**
347
+ * Headless reset-password form hook.
348
+ *
349
+ * Usage:
350
+ * const [searchParams] = useSearchParams();
351
+ * const token = searchParams.get("token") ?? "";
352
+ * const navigate = useNavigate();
353
+ *
354
+ * const { submit, loading, error } = useResetPasswordForm({
355
+ * token,
356
+ * onSuccess: () => navigate("/login"),
357
+ * });
358
+ *
359
+ * <form onSubmit={(e) => { e.preventDefault(); submit(newPassword); }}>
360
+ * …
361
+ * </form>
362
+ */
363
+ declare function useResetPasswordForm(options: UseResetPasswordFormOptions): UseResetPasswordFormReturn;
364
+
365
+ export { type AuthProviderProps as A, type LoginCredentials as L, type MessageOverrides as M, type OnErrorResult as O, type RefreshResponse as R, type SignupCredentials as S, type UseLoginFormOptions as U, type VisibilityConfig as V, type AuthContextValue as a, type AuthUser as b, type AuthSession as c, useSignupForm as d, useOtpForm as e, useForgotPasswordForm as f, useResetPasswordForm as g, type UseLoginFormReturn as h, type UseSignupFormOptions as i, type UseSignupFormReturn as j, type UseOtpFormOptions as k, type UseOtpFormReturn as l, type UseForgotPasswordFormOptions as m, type UseForgotPasswordFormReturn as n, type UseResetPasswordFormOptions as o, type UseResetPasswordFormReturn as p, type AuthState as q, type AuthConfig as r, type OAuthProvider as s, type SignupResult as t, useLoginForm as u, type UpdateProfileData as v, type AuthResponse as w };
package/dist/index.d.ts CHANGED
@@ -1,107 +1,5 @@
1
- interface AuthUser {
2
- id: string;
3
- email: string;
4
- email_verified: boolean;
5
- display_name: string | null;
6
- avatar_url: string | null;
7
- metadata: Record<string, unknown>;
8
- created_at: string;
9
- }
10
- interface AuthSession {
11
- access_token: string;
12
- refresh_token: string;
13
- expires_at: string;
14
- }
15
- interface AuthState {
16
- user: AuthUser | null;
17
- session: AuthSession | null;
18
- loading: boolean;
19
- error: string | null;
20
- }
21
- interface LoginCredentials {
22
- email: string;
23
- password: string;
24
- }
25
- interface SignupCredentials {
26
- email: string;
27
- password: string;
28
- displayName?: string;
29
- metadata?: Record<string, unknown>;
30
- }
31
- type OAuthProvider = "google" | "github" | "microsoft" | "facebook";
32
- interface AuthConfig {
33
- emailAuthEnabled: boolean;
34
- googleAuthEnabled: boolean;
35
- githubAuthEnabled: boolean;
36
- microsoftAuthEnabled: boolean;
37
- facebookAuthEnabled: boolean;
38
- allowSignup: boolean;
39
- requireEmailVerification: boolean;
40
- }
41
- interface VisibilityConfig {
42
- projectName: string;
43
- visibility: "public" | "private";
44
- requireLogin: boolean;
45
- logoUrl: string | null;
46
- welcomeMessage: string | null;
47
- }
48
- /**
49
- * Result of signup() — indicates what post-signup flow the caller should show.
50
- *
51
- * - `status: "authenticated"` — user is logged in, session is active. Redirect to app.
52
- * - `status: "needs_verification"` — email verification OTP was sent. Show OTP screen.
53
- * - `status: "needs_approval"` — account pending admin approval. Show waiting screen.
54
- */
55
- type SignupResult = {
56
- status: "authenticated";
57
- user: AuthUser;
58
- } | {
59
- status: "needs_verification";
60
- email: string;
61
- } | {
62
- status: "needs_approval";
63
- user: AuthUser;
64
- };
65
- interface AuthContextValue extends AuthState {
66
- login: (credentials: LoginCredentials) => Promise<void>;
67
- signup: (credentials: SignupCredentials) => Promise<SignupResult>;
68
- logout: () => Promise<void>;
69
- signInWithOAuth: (provider: OAuthProvider) => void;
70
- verifyOTP: (email: string, code: string) => Promise<void>;
71
- resendOTP: (email: string) => Promise<void>;
72
- updateProfile: (data: UpdateProfileData) => Promise<void>;
73
- refreshSession: () => Promise<void>;
74
- forgotPassword: (email: string) => Promise<void>;
75
- resetPassword: (token: string, newPassword: string) => Promise<void>;
76
- setProjectId: (projectId: string) => void;
77
- projectId: string | null;
78
- authConfig: AuthConfig | null;
79
- visibilityConfig: VisibilityConfig | null;
80
- }
81
- interface UpdateProfileData {
82
- displayName?: string;
83
- avatarUrl?: string;
84
- metadata?: Record<string, unknown>;
85
- }
86
- interface AuthProviderProps {
87
- children: React.ReactNode;
88
- projectId?: string;
89
- baseUrl?: string;
90
- persistSession?: boolean;
91
- onAuthStateChange?: (user: AuthUser | null) => void;
92
- }
93
- interface AuthResponse {
94
- user: AuthUser;
95
- session: AuthSession;
96
- /** Set when signup requires email verification — session is a placeholder with empty tokens. */
97
- needsVerification?: boolean;
98
- /** Set when signup succeeded but account is pending admin approval (private apps). */
99
- needsApproval?: boolean;
100
- }
101
- interface RefreshResponse {
102
- access_token: string;
103
- expires_at: string;
104
- }
1
+ import { A as AuthProviderProps, a as AuthContextValue, b as AuthUser, c as AuthSession } from './index-D4rCSC9H.js';
2
+ export { r as AuthConfig, w as AuthResponse, q as AuthState, L as LoginCredentials, M as MessageOverrides, s as OAuthProvider, O as OnErrorResult, R as RefreshResponse, S as SignupCredentials, t as SignupResult, v as UpdateProfileData, m as UseForgotPasswordFormOptions, n as UseForgotPasswordFormReturn, U as UseLoginFormOptions, h as UseLoginFormReturn, k as UseOtpFormOptions, l as UseOtpFormReturn, o as UseResetPasswordFormOptions, p as UseResetPasswordFormReturn, i as UseSignupFormOptions, j as UseSignupFormReturn, V as VisibilityConfig, f as useForgotPasswordForm, u as useLoginForm, e as useOtpForm, g as useResetPasswordForm, d as useSignupForm } from './index-D4rCSC9H.js';
105
3
 
106
4
  declare function AuthProvider({ children, projectId: initialProjectId, baseUrl, persistSession, onAuthStateChange, }: AuthProviderProps): JSX.Element;
107
5
  declare function useAuthContext(): AuthContextValue;
@@ -156,4 +54,4 @@ declare class AuthError extends Error {
156
54
  constructor(message: string, status: number, code?: string);
157
55
  }
158
56
 
159
- export { type AuthConfig, type AuthContextValue, AuthError, AuthProvider, type AuthProviderProps, type AuthResponse, type AuthSession, type AuthState, type AuthUser, type LoginCredentials, type OAuthProvider, type RefreshResponse, type SignupCredentials, type SignupResult, type UpdateProfileData, type VisibilityConfig, useAuth, useAuthContext, useAuthRequired, useSession, useUser };
57
+ export { AuthContextValue, AuthError, AuthProvider, AuthProviderProps, AuthSession, AuthUser, useAuth, useAuthContext, useAuthRequired, useSession, useUser };