@instroc/auth 1.0.1 → 1.0.2

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/dist/index.d.ts CHANGED
@@ -1,49 +1,49 @@
1
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;
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
9
  }
10
10
  interface AuthSession {
11
- access_token: string;
12
- refresh_token: string;
13
- expires_at: string;
11
+ access_token: string;
12
+ refresh_token: string;
13
+ expires_at: string;
14
14
  }
15
15
  interface AuthState {
16
- user: AuthUser | null;
17
- session: AuthSession | null;
18
- loading: boolean;
19
- error: string | null;
16
+ user: AuthUser | null;
17
+ session: AuthSession | null;
18
+ loading: boolean;
19
+ error: string | null;
20
20
  }
21
21
  interface LoginCredentials {
22
- email: string;
23
- password: string;
22
+ email: string;
23
+ password: string;
24
24
  }
25
25
  interface SignupCredentials {
26
- email: string;
27
- password: string;
28
- displayName?: string;
29
- metadata?: Record<string, unknown>;
26
+ email: string;
27
+ password: string;
28
+ displayName?: string;
29
+ metadata?: Record<string, unknown>;
30
30
  }
31
31
  type OAuthProvider = "google" | "github" | "microsoft" | "facebook";
32
32
  interface AuthConfig {
33
- emailAuthEnabled: boolean;
34
- googleAuthEnabled: boolean;
35
- githubAuthEnabled: boolean;
36
- microsoftAuthEnabled: boolean;
37
- facebookAuthEnabled: boolean;
38
- allowSignup: boolean;
39
- requireEmailVerification: boolean;
33
+ emailAuthEnabled: boolean;
34
+ googleAuthEnabled: boolean;
35
+ githubAuthEnabled: boolean;
36
+ microsoftAuthEnabled: boolean;
37
+ facebookAuthEnabled: boolean;
38
+ allowSignup: boolean;
39
+ requireEmailVerification: boolean;
40
40
  }
41
41
  interface VisibilityConfig {
42
- projectName: string;
43
- visibility: "public" | "private";
44
- requireLogin: boolean;
45
- logoUrl: string | null;
46
- welcomeMessage: string | null;
42
+ projectName: string;
43
+ visibility: "public" | "private";
44
+ requireLogin: boolean;
45
+ logoUrl: string | null;
46
+ welcomeMessage: string | null;
47
47
  }
48
48
  /**
49
49
  * Result of signup() — indicates what post-signup flow the caller should show.
@@ -52,108 +52,108 @@ interface VisibilityConfig {
52
52
  * - `status: "needs_verification"` — email verification OTP was sent. Show OTP screen.
53
53
  * - `status: "needs_approval"` — account pending admin approval. Show waiting screen.
54
54
  */
55
- type SignupResult =
56
- | {
57
- status: "authenticated";
58
- user: AuthUser;
59
- }
60
- | {
61
- status: "needs_verification";
62
- email: string;
63
- }
64
- | {
65
- status: "needs_approval";
66
- user: AuthUser;
67
- };
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
+ };
68
65
  interface AuthContextValue extends AuthState {
69
- login: (credentials: LoginCredentials) => Promise<void>;
70
- signup: (credentials: SignupCredentials) => Promise<SignupResult>;
71
- logout: () => Promise<void>;
72
- signInWithOAuth: (provider: OAuthProvider) => void;
73
- verifyOTP: (email: string, code: string) => Promise<void>;
74
- resendOTP: (email: string) => Promise<void>;
75
- updateProfile: (data: UpdateProfileData) => Promise<void>;
76
- refreshSession: () => Promise<void>;
77
- forgotPassword: (email: string) => Promise<void>;
78
- resetPassword: (token: string, newPassword: string) => Promise<void>;
79
- setProjectId: (projectId: string) => void;
80
- projectId: string | null;
81
- authConfig: AuthConfig | null;
82
- visibilityConfig: VisibilityConfig | null;
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;
83
80
  }
84
81
  interface UpdateProfileData {
85
- displayName?: string;
86
- avatarUrl?: string;
87
- metadata?: Record<string, unknown>;
82
+ displayName?: string;
83
+ avatarUrl?: string;
84
+ metadata?: Record<string, unknown>;
88
85
  }
89
86
  interface AuthProviderProps {
90
- children: React.ReactNode;
91
- projectId?: string;
92
- baseUrl?: string;
93
- persistSession?: boolean;
94
- onAuthStateChange?: (user: AuthUser | null) => void;
87
+ children: React.ReactNode;
88
+ projectId?: string;
89
+ baseUrl?: string;
90
+ persistSession?: boolean;
91
+ onAuthStateChange?: (user: AuthUser | null) => void;
95
92
  }
96
93
  interface AuthResponse {
97
- user: AuthUser;
98
- session: AuthSession;
99
- /** Set when signup requires email verification — session is a placeholder with empty tokens. */
100
- needsVerification?: boolean;
101
- /** Set when signup succeeded but account is pending admin approval (private apps). */
102
- needsApproval?: boolean;
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;
103
100
  }
104
101
  interface RefreshResponse {
105
- access_token: string;
106
- expires_at: string;
102
+ access_token: string;
103
+ expires_at: string;
107
104
  }
108
105
 
109
- declare function AuthProvider({
110
- children,
111
- projectId: initialProjectId,
112
- baseUrl,
113
- persistSession,
114
- onAuthStateChange,
115
- }: AuthProviderProps): JSX.Element;
106
+ declare function AuthProvider({ children, projectId: initialProjectId, baseUrl, persistSession, onAuthStateChange, }: AuthProviderProps): JSX.Element;
116
107
  declare function useAuthContext(): AuthContextValue;
117
108
 
118
109
  declare function useAuth(): AuthContextValue;
119
110
  declare function useUser(): {
120
- user: AuthUser | null;
121
- loading: boolean;
111
+ user: AuthUser | null;
112
+ loading: boolean;
122
113
  };
123
114
  declare function useSession(): {
124
- session: AuthSession | null;
125
- loading: boolean;
115
+ session: AuthSession | null;
116
+ loading: boolean;
126
117
  };
127
- declare function useAuthRequired():
128
- | {
129
- user: null;
130
- session: null;
131
- loading: boolean;
132
- }
133
- | {
134
- user: AuthUser;
135
- session: AuthSession | null;
136
- loading: boolean;
137
- };
138
-
139
- export {
140
- type AuthConfig,
141
- type AuthContextValue,
142
- AuthProvider,
143
- type AuthProviderProps,
144
- type AuthResponse,
145
- type AuthSession,
146
- type AuthState,
147
- type AuthUser,
148
- type LoginCredentials,
149
- type OAuthProvider,
150
- type RefreshResponse,
151
- type SignupCredentials,
152
- type UpdateProfileData,
153
- type VisibilityConfig,
154
- useAuth,
155
- useAuthContext,
156
- useAuthRequired,
157
- useSession,
158
- useUser,
118
+ declare function useAuthRequired(): {
119
+ user: null;
120
+ session: null;
121
+ loading: boolean;
122
+ } | {
123
+ user: AuthUser;
124
+ session: AuthSession | null;
125
+ loading: boolean;
159
126
  };
127
+
128
+ /**
129
+ * Typed error thrown by every `@instroc/auth` method when the server responds
130
+ * with a non-2xx status. Carries the HTTP status so consumers can branch on
131
+ * behavioural outcomes (429 = cooldown UI, 403 = redirect to OTP page, etc.)
132
+ * without string-matching the message.
133
+ *
134
+ * Usage:
135
+ * try {
136
+ * await login({ email, password });
137
+ * } catch (err) {
138
+ * if (err instanceof AuthError) {
139
+ * if (err.status === 429) { setCooldown(60); return; }
140
+ * if (err.status === 403) { onNeedsVerification?.(email); return; }
141
+ * setLocalError(err.message);
142
+ * } else {
143
+ * setLocalError("An unexpected error occurred.");
144
+ * }
145
+ * }
146
+ */
147
+ declare class AuthError extends Error {
148
+ /** HTTP status code from the server (400, 401, 403, 404, 409, 429, 500…). */
149
+ readonly status: number;
150
+ /**
151
+ * Optional machine-readable error code from the server (e.g. `"invalid_credentials"`,
152
+ * `"email_not_verified"`). Present when the server includes a `code` field in the
153
+ * error body; otherwise `undefined`.
154
+ */
155
+ readonly code?: string;
156
+ constructor(message: string, status: number, code?: string);
157
+ }
158
+
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 };
package/dist/index.js CHANGED
@@ -7,6 +7,24 @@ import {
7
7
  useEffect,
8
8
  useRef
9
9
  } from "react";
10
+
11
+ // src/errors.ts
12
+ var AuthError = class _AuthError extends Error {
13
+ constructor(message, status, code) {
14
+ super(message);
15
+ this.name = "AuthError";
16
+ this.status = status;
17
+ this.code = code;
18
+ Object.setPrototypeOf(this, _AuthError.prototype);
19
+ }
20
+ };
21
+ function authErrorFromResponse(response, data, fallbackMessage) {
22
+ const body = data ?? {};
23
+ const message = body.error || fallbackMessage;
24
+ return new AuthError(message, response.status, body.code);
25
+ }
26
+
27
+ // src/provider.tsx
10
28
  import { jsx } from "react/jsx-runtime";
11
29
  var AuthContext = createContext(null);
12
30
  var STORAGE_KEY = "instroc_auth_session";
@@ -182,7 +200,7 @@ function AuthProvider({
182
200
  });
183
201
  const data = await response.json();
184
202
  if (!response.ok) {
185
- throw new Error(data.error || "Login failed");
203
+ throw authErrorFromResponse(response, data, "Login failed");
186
204
  }
187
205
  const authResponse = data;
188
206
  updateAuthState(authResponse.user, authResponse.session);
@@ -208,7 +226,7 @@ function AuthProvider({
208
226
  });
209
227
  const data = await response.json();
210
228
  if (!response.ok) {
211
- throw new Error(data.error || "Signup failed");
229
+ throw authErrorFromResponse(response, data, "Signup failed");
212
230
  }
213
231
  const authResponse = data;
214
232
  if (authResponse.needsVerification) {
@@ -261,7 +279,7 @@ function AuthProvider({
261
279
  const updateProfile = useCallback(
262
280
  async (data) => {
263
281
  if (!session) {
264
- throw new Error("Not authenticated");
282
+ throw new AuthError("Not authenticated", 401);
265
283
  }
266
284
  setError(null);
267
285
  try {
@@ -275,7 +293,7 @@ function AuthProvider({
275
293
  });
276
294
  const result = await response.json();
277
295
  if (!response.ok) {
278
- throw new Error(result.error || "Update failed");
296
+ throw authErrorFromResponse(response, result, "Update failed");
279
297
  }
280
298
  setUser(result.user);
281
299
  } catch (err) {
@@ -296,7 +314,7 @@ function AuthProvider({
296
314
  });
297
315
  const data = await response.json();
298
316
  if (!response.ok) {
299
- throw new Error(data.error || "Refresh failed");
317
+ throw authErrorFromResponse(response, data, "Refresh failed");
300
318
  }
301
319
  const refreshData = data;
302
320
  const newSession = {
@@ -317,7 +335,7 @@ function AuthProvider({
317
335
  });
318
336
  const data = await response.json();
319
337
  if (!response.ok) {
320
- throw new Error(data.error || "Request failed");
338
+ throw authErrorFromResponse(response, data, "Request failed");
321
339
  }
322
340
  } catch (err) {
323
341
  const message = err instanceof Error ? err.message : "Request failed";
@@ -338,7 +356,7 @@ function AuthProvider({
338
356
  });
339
357
  const data = await response.json();
340
358
  if (!response.ok) {
341
- throw new Error(data.error || "Reset failed");
359
+ throw authErrorFromResponse(response, data, "Reset failed");
342
360
  }
343
361
  } catch (err) {
344
362
  const message = err instanceof Error ? err.message : "Reset failed";
@@ -372,7 +390,7 @@ function AuthProvider({
372
390
  });
373
391
  const data = await response.json();
374
392
  if (!response.ok) {
375
- throw new Error(data.error || "Verification failed");
393
+ throw authErrorFromResponse(response, data, "Verification failed");
376
394
  }
377
395
  if (data.session) {
378
396
  updateAuthState(data.user, data.session);
@@ -398,7 +416,7 @@ function AuthProvider({
398
416
  });
399
417
  const data = await response.json();
400
418
  if (!response.ok) {
401
- throw new Error(data.error || "Failed to resend code");
419
+ throw authErrorFromResponse(response, data, "Failed to resend code");
402
420
  }
403
421
  } catch (err) {
404
422
  const message = err instanceof Error ? err.message : "Failed to resend code";
@@ -541,6 +559,7 @@ function useAuthRequired() {
541
559
  return { user, session, loading: false };
542
560
  }
543
561
  export {
562
+ AuthError,
544
563
  AuthProvider,
545
564
  useAuth,
546
565
  useAuthContext,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instroc/auth",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Authentication hooks for Instroc Cloud — useAuth, useUser, AuthProvider",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",