authfort-client 0.0.1 → 0.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/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # authfort-client
2
+
3
+ TypeScript client SDK for AuthFort authentication.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install authfort-client
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import { createAuthClient } from 'authfort-client';
15
+
16
+ const auth = createAuthClient({
17
+ baseUrl: '/auth',
18
+ tokenMode: 'cookie', // or 'bearer'
19
+ });
20
+
21
+ await auth.initialize();
22
+
23
+ // Sign up / sign in
24
+ await auth.signUp({ email: 'user@example.com', password: 'secret' });
25
+ await auth.signIn({ email: 'user@example.com', password: 'secret' });
26
+
27
+ // Authenticated fetch (auto-attaches credentials, retries on 401)
28
+ const res = await auth.fetch('/api/profile');
29
+
30
+ // OAuth
31
+ auth.signInWithProvider('google');
32
+
33
+ // Listen for auth state changes
34
+ auth.onAuthStateChange((state, user) => {
35
+ console.log(state, user);
36
+ });
37
+
38
+ // Sign out
39
+ await auth.signOut();
40
+ ```
41
+
42
+ ## React
43
+
44
+ ```tsx
45
+ import { AuthProvider, useAuth } from 'authfort-client/react';
46
+
47
+ // Wrap your app
48
+ <AuthProvider client={auth}><App /></AuthProvider>
49
+
50
+ // In components
51
+ function Profile() {
52
+ const { user, isAuthenticated, client } = useAuth();
53
+ if (!isAuthenticated) return <p>Not signed in</p>;
54
+ return <p>Hello {user.email}</p>;
55
+ }
56
+ ```
57
+
58
+ ## Vue
59
+
60
+ ```vue
61
+ <script setup>
62
+ import { provideAuth, useAuth } from 'authfort-client/vue';
63
+
64
+ provideAuth(auth); // in root component
65
+
66
+ const { user, isAuthenticated } = useAuth(); // in any child
67
+ </script>
68
+ ```
69
+
70
+ ## Svelte
71
+
72
+ ```svelte
73
+ <script>
74
+ import { createAuthStore } from 'authfort-client/svelte';
75
+
76
+ const { user, isAuthenticated, client } = createAuthStore(auth);
77
+ </script>
78
+
79
+ {#if $isAuthenticated}
80
+ Hello {$user.email}
81
+ {/if}
82
+ ```
83
+
84
+ ## Authenticated Requests
85
+
86
+ `auth.fetch()` is native `fetch` with auth added — same `RequestInit`, same `Response`. Headers, streaming, AbortController all work as normal.
87
+
88
+ ```typescript
89
+ // JSON POST
90
+ const res = await auth.fetch('/api/data', {
91
+ method: 'POST',
92
+ headers: { 'Content-Type': 'application/json' },
93
+ body: JSON.stringify({ name: 'test' }),
94
+ });
95
+
96
+ // Streaming
97
+ const stream = await auth.fetch('/api/stream');
98
+ const reader = stream.body.getReader();
99
+
100
+ // AbortController
101
+ const controller = new AbortController();
102
+ await auth.fetch('/api/slow', { signal: controller.signal });
103
+ ```
104
+
105
+ If a request gets a 401, it automatically refreshes the token and retries once. Multiple concurrent 401s share a single refresh call.
106
+
107
+ ### Using with Axios / TanStack Query (bearer mode)
108
+
109
+ In cookie mode, any HTTP client works out of the box — the browser sends cookies automatically. In bearer mode, if you prefer your own HTTP client over `auth.fetch()`, use `getToken()` to get a valid token:
110
+
111
+ ```typescript
112
+ // Axios interceptor
113
+ axios.interceptors.request.use(async (config) => {
114
+ const token = await auth.getToken();
115
+ if (token) config.headers.Authorization = `Bearer ${token}`;
116
+ return config;
117
+ });
118
+
119
+ // TanStack Query
120
+ const { data } = useQuery({
121
+ queryKey: ['profile'],
122
+ queryFn: async () => {
123
+ const token = await auth.getToken();
124
+ const res = await fetch('/api/profile', {
125
+ headers: { Authorization: `Bearer ${token}` },
126
+ });
127
+ return res.json();
128
+ },
129
+ });
130
+ ```
131
+
132
+ `getToken()` automatically refreshes if the token is expired, and deduplicates concurrent refresh calls.
133
+
134
+ ## Token Modes
135
+
136
+ - **cookie** (default) — httponly cookies, JS never touches tokens
137
+ - **bearer** — access token in memory, `Authorization: Bearer` header
138
+
139
+ ## License
140
+
141
+ [MIT](../LICENSE)
@@ -0,0 +1,7 @@
1
+ /**
2
+ * AuthFort client — main implementation.
3
+ */
4
+ import type { AuthClient, AuthClientConfig } from './types';
5
+ /** Create an AuthFort client instance. */
6
+ export declare function createAuthClient(config: AuthClientConfig): AuthClient;
7
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAKjB,MAAM,SAAS,CAAC;AAwRjB,0CAA0C;AAC1C,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAErE"}
package/dist/client.js ADDED
@@ -0,0 +1,236 @@
1
+ /**
2
+ * AuthFort client — main implementation.
3
+ */
4
+ import { parseErrorResponse } from './errors';
5
+ import { TokenManager } from './token-manager';
6
+ // ---------------------------------------------------------------------------
7
+ // Helpers
8
+ // ---------------------------------------------------------------------------
9
+ function mapUser(server) {
10
+ return {
11
+ id: server.id,
12
+ email: server.email,
13
+ name: server.name ?? undefined,
14
+ roles: server.roles,
15
+ emailVerified: server.email_verified,
16
+ avatarUrl: server.avatar_url ?? undefined,
17
+ createdAt: server.created_at,
18
+ };
19
+ }
20
+ // ---------------------------------------------------------------------------
21
+ // Implementation
22
+ // ---------------------------------------------------------------------------
23
+ class AuthClientImpl {
24
+ constructor(config) {
25
+ this._state = 'unauthenticated';
26
+ this._user = null;
27
+ this._listeners = new Set();
28
+ this._tokenManager = null;
29
+ this._baseUrl = config.baseUrl.replace(/\/+$/, '');
30
+ this._tokenMode = config.tokenMode ?? 'cookie';
31
+ if (this._tokenMode === 'bearer') {
32
+ this._tokenManager = new TokenManager(this._baseUrl, config.refreshBuffer ?? 30, (response) => this._setAuthenticated(mapUser(response.user)), () => this._setState('unauthenticated', null));
33
+ }
34
+ }
35
+ async initialize() {
36
+ this._setState('loading', null);
37
+ try {
38
+ if (this._tokenMode === 'bearer') {
39
+ const result = await this._tokenManager.refresh();
40
+ if (!result) {
41
+ this._setState('unauthenticated', null);
42
+ }
43
+ // onRefreshSuccess already called _setAuthenticated
44
+ }
45
+ else {
46
+ // Cookie mode: try /me, then /refresh on 401
47
+ const meResponse = await fetch(`${this._baseUrl}/me`, {
48
+ credentials: 'include',
49
+ });
50
+ if (meResponse.ok) {
51
+ const serverUser = await meResponse.json();
52
+ this._setAuthenticated(mapUser(serverUser));
53
+ }
54
+ else if (meResponse.status === 401) {
55
+ // Access cookie expired — try refreshing
56
+ const refreshResponse = await fetch(`${this._baseUrl}/refresh`, {
57
+ method: 'POST',
58
+ credentials: 'include',
59
+ headers: { 'Content-Type': 'application/json' },
60
+ body: JSON.stringify({}),
61
+ });
62
+ if (refreshResponse.ok) {
63
+ const data = await refreshResponse.json();
64
+ this._setAuthenticated(mapUser(data.user));
65
+ }
66
+ else {
67
+ this._setState('unauthenticated', null);
68
+ }
69
+ }
70
+ else {
71
+ this._setState('unauthenticated', null);
72
+ }
73
+ }
74
+ }
75
+ catch {
76
+ this._setState('unauthenticated', null);
77
+ }
78
+ }
79
+ async getToken() {
80
+ if (this._tokenMode === 'cookie') {
81
+ return null;
82
+ }
83
+ const token = this._tokenManager.getToken();
84
+ if (token)
85
+ return token;
86
+ // Token expired or absent — try refresh
87
+ const result = await this._tokenManager.refresh();
88
+ return result ? result.tokens.access_token : null;
89
+ }
90
+ async fetch(url, options = {}) {
91
+ const doFetch = async () => {
92
+ const fetchOptions = { ...options };
93
+ if (this._tokenMode === 'cookie') {
94
+ fetchOptions.credentials = 'include';
95
+ }
96
+ else {
97
+ const token = await this.getToken();
98
+ if (token) {
99
+ fetchOptions.headers = {
100
+ ...fetchOptions.headers,
101
+ Authorization: `Bearer ${token}`,
102
+ };
103
+ }
104
+ fetchOptions.credentials = 'include';
105
+ }
106
+ return globalThis.fetch(url, fetchOptions);
107
+ };
108
+ let response = await doFetch();
109
+ // 401 retry: refresh then retry once
110
+ if (response.status === 401) {
111
+ let refreshed = false;
112
+ if (this._tokenMode === 'bearer') {
113
+ this._tokenManager.clear();
114
+ const result = await this._tokenManager.refresh();
115
+ refreshed = result !== null;
116
+ }
117
+ else {
118
+ const refreshResponse = await globalThis.fetch(`${this._baseUrl}/refresh`, {
119
+ method: 'POST',
120
+ credentials: 'include',
121
+ headers: { 'Content-Type': 'application/json' },
122
+ body: JSON.stringify({}),
123
+ });
124
+ refreshed = refreshResponse.ok;
125
+ }
126
+ if (refreshed) {
127
+ response = await doFetch();
128
+ }
129
+ // Still 401 after retry — session is dead
130
+ if (response.status === 401) {
131
+ if (this._tokenManager)
132
+ this._tokenManager.clear();
133
+ this._setState('unauthenticated', null);
134
+ }
135
+ }
136
+ return response;
137
+ }
138
+ async signUp(data) {
139
+ const response = await globalThis.fetch(`${this._baseUrl}/signup`, {
140
+ method: 'POST',
141
+ credentials: 'include',
142
+ headers: { 'Content-Type': 'application/json' },
143
+ body: JSON.stringify(data),
144
+ });
145
+ if (!response.ok) {
146
+ throw await parseErrorResponse(response);
147
+ }
148
+ const result = await response.json();
149
+ const user = mapUser(result.user);
150
+ if (this._tokenManager) {
151
+ this._tokenManager.setTokens(result.tokens.access_token, result.tokens.expires_in);
152
+ }
153
+ this._setAuthenticated(user);
154
+ return user;
155
+ }
156
+ async signIn(data) {
157
+ const response = await globalThis.fetch(`${this._baseUrl}/login`, {
158
+ method: 'POST',
159
+ credentials: 'include',
160
+ headers: { 'Content-Type': 'application/json' },
161
+ body: JSON.stringify(data),
162
+ });
163
+ if (!response.ok) {
164
+ throw await parseErrorResponse(response);
165
+ }
166
+ const result = await response.json();
167
+ const user = mapUser(result.user);
168
+ if (this._tokenManager) {
169
+ this._tokenManager.setTokens(result.tokens.access_token, result.tokens.expires_in);
170
+ }
171
+ this._setAuthenticated(user);
172
+ return user;
173
+ }
174
+ signInWithProvider(provider) {
175
+ window.location.href = `${this._baseUrl}/oauth/${provider}/authorize`;
176
+ }
177
+ async signOut() {
178
+ try {
179
+ await globalThis.fetch(`${this._baseUrl}/logout`, {
180
+ method: 'POST',
181
+ credentials: 'include',
182
+ headers: { 'Content-Type': 'application/json' },
183
+ body: JSON.stringify({}),
184
+ });
185
+ }
186
+ finally {
187
+ if (this._tokenManager)
188
+ this._tokenManager.clear();
189
+ this._setState('unauthenticated', null);
190
+ }
191
+ }
192
+ async getUser() {
193
+ const response = await this.fetch(`${this._baseUrl}/me`);
194
+ if (!response.ok) {
195
+ throw await parseErrorResponse(response);
196
+ }
197
+ const serverUser = await response.json();
198
+ const user = mapUser(serverUser);
199
+ this._user = user;
200
+ return user;
201
+ }
202
+ onAuthStateChange(callback) {
203
+ this._listeners.add(callback);
204
+ // Fire immediately with current state
205
+ callback(this._state, this._user);
206
+ return () => {
207
+ this._listeners.delete(callback);
208
+ };
209
+ }
210
+ // ---------------------------------------------------------------------------
211
+ // Private
212
+ // ---------------------------------------------------------------------------
213
+ _setAuthenticated(user) {
214
+ this._setState('authenticated', user);
215
+ }
216
+ _setState(state, user) {
217
+ const changed = this._state !== state || this._user !== user;
218
+ this._state = state;
219
+ this._user = user;
220
+ if (changed) {
221
+ for (const listener of this._listeners) {
222
+ try {
223
+ listener(state, user);
224
+ }
225
+ catch {
226
+ // Don't break on listener errors
227
+ }
228
+ }
229
+ }
230
+ }
231
+ }
232
+ /** Create an AuthFort client instance. */
233
+ export function createAuthClient(config) {
234
+ return new AuthClientImpl(config);
235
+ }
236
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ /** Error thrown by AuthFort client operations. */
2
+ export declare class AuthClientError extends Error {
3
+ /** Server error code (e.g., "invalid_credentials", "user_exists") */
4
+ readonly code: string;
5
+ /** HTTP status code from the server response */
6
+ readonly statusCode: number;
7
+ constructor(message: string, code: string, statusCode: number);
8
+ }
9
+ /**
10
+ * Parse an error response from the AuthFort server.
11
+ * FastAPI wraps errors as { detail: { error, message } }.
12
+ */
13
+ export declare function parseErrorResponse(response: Response): Promise<AuthClientError>;
14
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,qBAAa,eAAgB,SAAQ,KAAK;IACxC,qEAAqE;IACrE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;CAM9D;AAED;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,eAAe,CAAC,CAgB1B"}
package/dist/errors.js ADDED
@@ -0,0 +1,24 @@
1
+ /** Error thrown by AuthFort client operations. */
2
+ export class AuthClientError extends Error {
3
+ constructor(message, code, statusCode) {
4
+ super(message);
5
+ this.name = 'AuthClientError';
6
+ this.code = code;
7
+ this.statusCode = statusCode;
8
+ }
9
+ }
10
+ /**
11
+ * Parse an error response from the AuthFort server.
12
+ * FastAPI wraps errors as { detail: { error, message } }.
13
+ */
14
+ export async function parseErrorResponse(response) {
15
+ try {
16
+ const body = await response.json();
17
+ const detail = body.detail ?? body;
18
+ return new AuthClientError(detail.message ?? response.statusText, detail.error ?? 'unknown_error', response.status);
19
+ }
20
+ catch {
21
+ return new AuthClientError(response.statusText, 'unknown_error', response.status);
22
+ }
23
+ }
24
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,kDAAkD;AAClD,MAAM,OAAO,eAAgB,SAAQ,KAAK;IAMxC,YAAY,OAAe,EAAE,IAAY,EAAE,UAAkB;QAC3D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,iBAAiB,CAAC;QAC9B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;IAC/B,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,QAAkB;IAElB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC;QACnC,OAAO,IAAI,eAAe,CACxB,MAAM,CAAC,OAAO,IAAI,QAAQ,CAAC,UAAU,EACrC,MAAM,CAAC,KAAK,IAAI,eAAe,EAC/B,QAAQ,CAAC,MAAM,CAChB,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,eAAe,CACxB,QAAQ,CAAC,UAAU,EACnB,eAAe,EACf,QAAQ,CAAC,MAAM,CAChB,CAAC;IACJ,CAAC;AACH,CAAC"}
@@ -3,6 +3,7 @@
3
3
  *
4
4
  * Handles token lifecycle, proactive refresh, and authenticated requests.
5
5
  */
6
-
7
6
  export { createAuthClient } from './client';
7
+ export { AuthClientError } from './errors';
8
8
  export type { AuthClientConfig, AuthClient, AuthState, AuthUser } from './types';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC3C,YAAY,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * AuthFort Client — TypeScript SDK for AuthFort authentication.
3
+ *
4
+ * Handles token lifecycle, proactive refresh, and authenticated requests.
5
+ */
6
+ export { createAuthClient } from './client';
7
+ export { AuthClientError } from './errors';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * React hooks for AuthFort.
3
+ *
4
+ * Usage:
5
+ * import { AuthProvider, useAuth } from 'authfort-client/react';
6
+ *
7
+ * // Wrap your app
8
+ * <AuthProvider client={auth}><App /></AuthProvider>
9
+ *
10
+ * // Use in any component
11
+ * const { user, isAuthenticated, client } = useAuth();
12
+ */
13
+ import { type ReactNode } from 'react';
14
+ import type { AuthClient, AuthState, AuthUser } from '../types';
15
+ /** Props for AuthProvider */
16
+ export interface AuthProviderProps {
17
+ client: AuthClient;
18
+ children: ReactNode;
19
+ }
20
+ /** Provides the AuthFort client to all child components. */
21
+ export declare function AuthProvider({ client, children }: AuthProviderProps): import("react/jsx-runtime").JSX.Element;
22
+ /** Return type of useAuth() */
23
+ export interface UseAuthReturn {
24
+ /** Current auth state */
25
+ state: AuthState;
26
+ /** Current user (null when not authenticated) */
27
+ user: AuthUser | null;
28
+ /** Whether the user is authenticated */
29
+ isAuthenticated: boolean;
30
+ /** Whether auth state is being determined */
31
+ isLoading: boolean;
32
+ /** The AuthFort client instance (for signIn, signOut, fetch, etc.) */
33
+ client: AuthClient;
34
+ }
35
+ /**
36
+ * React hook for AuthFort auth state.
37
+ * Must be used inside an AuthProvider.
38
+ */
39
+ export declare function useAuth(): UseAuthReturn;
40
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAQhE,6BAA6B;AAC7B,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,iBAAiB,2CAEnE;AAMD,+BAA+B;AAC/B,MAAM,WAAW,aAAa;IAC5B,yBAAyB;IACzB,KAAK,EAAE,SAAS,CAAC;IACjB,iDAAiD;IACjD,IAAI,EAAE,QAAQ,GAAG,IAAI,CAAC;IACtB,wCAAwC;IACxC,eAAe,EAAE,OAAO,CAAC;IACzB,6CAA6C;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,sEAAsE;IACtE,MAAM,EAAE,UAAU,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,OAAO,IAAI,aAAa,CAuBvC"}
@@ -0,0 +1,48 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ /**
3
+ * React hooks for AuthFort.
4
+ *
5
+ * Usage:
6
+ * import { AuthProvider, useAuth } from 'authfort-client/react';
7
+ *
8
+ * // Wrap your app
9
+ * <AuthProvider client={auth}><App /></AuthProvider>
10
+ *
11
+ * // Use in any component
12
+ * const { user, isAuthenticated, client } = useAuth();
13
+ */
14
+ import { createContext, useContext, useState, useEffect, } from 'react';
15
+ // ---------------------------------------------------------------------------
16
+ // Context
17
+ // ---------------------------------------------------------------------------
18
+ const AuthContext = createContext(null);
19
+ /** Provides the AuthFort client to all child components. */
20
+ export function AuthProvider({ client, children }) {
21
+ return _jsx(AuthContext.Provider, { value: client, children: children });
22
+ }
23
+ /**
24
+ * React hook for AuthFort auth state.
25
+ * Must be used inside an AuthProvider.
26
+ */
27
+ export function useAuth() {
28
+ const client = useContext(AuthContext);
29
+ if (!client) {
30
+ throw new Error('useAuth() must be used inside <AuthProvider>');
31
+ }
32
+ const [state, setState] = useState('unauthenticated');
33
+ const [user, setUser] = useState(null);
34
+ useEffect(() => {
35
+ return client.onAuthStateChange((s, u) => {
36
+ setState(s);
37
+ setUser(u);
38
+ });
39
+ }, [client]);
40
+ return {
41
+ state,
42
+ user,
43
+ isAuthenticated: state === 'authenticated',
44
+ isLoading: state === 'loading',
45
+ client,
46
+ };
47
+ }
48
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.tsx"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,aAAa,EACb,UAAU,EACV,QAAQ,EACR,SAAS,GAEV,MAAM,OAAO,CAAC;AAGf,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,MAAM,WAAW,GAAG,aAAa,CAAoB,IAAI,CAAC,CAAC;AAQ3D,4DAA4D;AAC5D,MAAM,UAAU,YAAY,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAqB;IAClE,OAAO,KAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,MAAM,YAAG,QAAQ,GAAwB,CAAC;AAChF,CAAC;AAoBD;;;GAGG;AACH,MAAM,UAAU,OAAO;IACrB,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CAAC;IACvC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,8CAA8C,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAY,iBAAiB,CAAC,CAAC;IACjE,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,QAAQ,CAAkB,IAAI,CAAC,CAAC;IAExD,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YACvC,QAAQ,CAAC,CAAC,CAAC,CAAC;YACZ,OAAO,CAAC,CAAC,CAAC,CAAC;QACb,CAAC,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC;IAEb,OAAO;QACL,KAAK;QACL,IAAI;QACJ,eAAe,EAAE,KAAK,KAAK,eAAe;QAC1C,SAAS,EAAE,KAAK,KAAK,SAAS;QAC9B,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Svelte stores for AuthFort.
3
+ *
4
+ * Usage:
5
+ * import { createAuthStore } from 'authfort-client/svelte';
6
+ *
7
+ * // Create once (e.g., in auth.ts)
8
+ * export const authStore = createAuthStore(auth);
9
+ *
10
+ * // Use in components
11
+ * const { state, user, isAuthenticated } = authStore;
12
+ * {#if $isAuthenticated} Hello {$user.email} {/if}
13
+ */
14
+ import { type Readable } from 'svelte/store';
15
+ import type { AuthClient, AuthState, AuthUser } from '../types';
16
+ /** Return type of createAuthStore() */
17
+ export interface AuthStore {
18
+ /** Current auth state (readable store) */
19
+ state: Readable<AuthState>;
20
+ /** Current user (readable store, null when not authenticated) */
21
+ user: Readable<AuthUser | null>;
22
+ /** Whether the user is authenticated (derived store) */
23
+ isAuthenticated: Readable<boolean>;
24
+ /** Whether auth state is being determined (derived store) */
25
+ isLoading: Readable<boolean>;
26
+ /** The AuthFort client instance */
27
+ client: AuthClient;
28
+ }
29
+ /**
30
+ * Create a Svelte store that tracks AuthFort auth state.
31
+ * Call once at module level and export for use in components.
32
+ */
33
+ export declare function createAuthStore(client: AuthClient): AuthStore;
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAqB,KAAK,QAAQ,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAMhE,uCAAuC;AACvC,MAAM,WAAW,SAAS;IACxB,0CAA0C;IAC1C,KAAK,EAAE,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC3B,iEAAiE;IACjE,IAAI,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC;IAChC,wDAAwD;IACxD,eAAe,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnC,6DAA6D;IAC7D,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC;IAC7B,mCAAmC;IACnC,MAAM,EAAE,UAAU,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAgB7D"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Svelte stores for AuthFort.
3
+ *
4
+ * Usage:
5
+ * import { createAuthStore } from 'authfort-client/svelte';
6
+ *
7
+ * // Create once (e.g., in auth.ts)
8
+ * export const authStore = createAuthStore(auth);
9
+ *
10
+ * // Use in components
11
+ * const { state, user, isAuthenticated } = authStore;
12
+ * {#if $isAuthenticated} Hello {$user.email} {/if}
13
+ */
14
+ import { writable, derived } from 'svelte/store';
15
+ /**
16
+ * Create a Svelte store that tracks AuthFort auth state.
17
+ * Call once at module level and export for use in components.
18
+ */
19
+ export function createAuthStore(client) {
20
+ const state = writable('unauthenticated');
21
+ const user = writable(null);
22
+ client.onAuthStateChange((s, u) => {
23
+ state.set(s);
24
+ user.set(u);
25
+ });
26
+ return {
27
+ state: { subscribe: state.subscribe },
28
+ user: { subscribe: user.subscribe },
29
+ isAuthenticated: derived(state, ($s) => $s === 'authenticated'),
30
+ isLoading: derived(state, ($s) => $s === 'loading'),
31
+ client,
32
+ };
33
+ }
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/svelte/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAiB,MAAM,cAAc,CAAC;AAqBhE;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,MAAkB;IAChD,MAAM,KAAK,GAAG,QAAQ,CAAY,iBAAiB,CAAC,CAAC;IACrD,MAAM,IAAI,GAAG,QAAQ,CAAkB,IAAI,CAAC,CAAC;IAE7C,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAChC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACb,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACd,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAyB;QAC5D,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAA+B;QAChE,eAAe,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,eAAe,CAAC;QAC/D,SAAS,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,KAAK,SAAS,CAAC;QACnD,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Token lifecycle manager (bearer mode only).
3
+ *
4
+ * Handles:
5
+ * - In-memory access token storage
6
+ * - Proactive refresh (before expiry)
7
+ * - Single refresh promise deduplication
8
+ */
9
+ import type { ServerAuthResponse } from './types';
10
+ export declare class TokenManager {
11
+ private readonly _baseUrl;
12
+ private readonly _refreshBuffer;
13
+ private readonly _onRefreshSuccess;
14
+ private readonly _onRefreshFailure;
15
+ private _accessToken;
16
+ private _expiresAt;
17
+ private _refreshTimer;
18
+ private _refreshPromise;
19
+ constructor(_baseUrl: string, _refreshBuffer: number, _onRefreshSuccess: (response: ServerAuthResponse) => void, _onRefreshFailure: () => void);
20
+ /** Returns the current access token, or null if expired/absent. */
21
+ getToken(): string | null;
22
+ /** Store a new access token and schedule proactive refresh. */
23
+ setTokens(accessToken: string, expiresIn: number): void;
24
+ /** Clear stored token and cancel any scheduled refresh. */
25
+ clear(): void;
26
+ /**
27
+ * Refresh the access token via POST /refresh (using refresh cookie).
28
+ * Deduplicates concurrent calls — only one fetch in flight at a time.
29
+ */
30
+ refresh(): Promise<ServerAuthResponse | null>;
31
+ /** Cleanup timers. */
32
+ dispose(): void;
33
+ private _doRefresh;
34
+ private _scheduleRefresh;
35
+ private _cancelRefresh;
36
+ }
37
+ //# sourceMappingURL=token-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../src/token-manager.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAElD,qBAAa,YAAY;IAOrB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAClC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IATpC,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,aAAa,CAA8C;IACnE,OAAO,CAAC,eAAe,CAAmD;gBAGvD,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,iBAAiB,EAAE,CAAC,QAAQ,EAAE,kBAAkB,KAAK,IAAI,EACzD,iBAAiB,EAAE,MAAM,IAAI;IAGhD,mEAAmE;IACnE,QAAQ,IAAI,MAAM,GAAG,IAAI;IAOzB,+DAA+D;IAC/D,SAAS,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI;IAMvD,2DAA2D;IAC3D,KAAK,IAAI,IAAI;IAMb;;;OAGG;IACG,OAAO,IAAI,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC;IAanD,sBAAsB;IACtB,OAAO,IAAI,IAAI;YAQD,UAAU;IA0BxB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,cAAc;CAMvB"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Token lifecycle manager (bearer mode only).
3
+ *
4
+ * Handles:
5
+ * - In-memory access token storage
6
+ * - Proactive refresh (before expiry)
7
+ * - Single refresh promise deduplication
8
+ */
9
+ export class TokenManager {
10
+ constructor(_baseUrl, _refreshBuffer, _onRefreshSuccess, _onRefreshFailure) {
11
+ this._baseUrl = _baseUrl;
12
+ this._refreshBuffer = _refreshBuffer;
13
+ this._onRefreshSuccess = _onRefreshSuccess;
14
+ this._onRefreshFailure = _onRefreshFailure;
15
+ this._accessToken = null;
16
+ this._expiresAt = 0;
17
+ this._refreshTimer = null;
18
+ this._refreshPromise = null;
19
+ }
20
+ /** Returns the current access token, or null if expired/absent. */
21
+ getToken() {
22
+ if (this._accessToken && Date.now() < this._expiresAt) {
23
+ return this._accessToken;
24
+ }
25
+ return null;
26
+ }
27
+ /** Store a new access token and schedule proactive refresh. */
28
+ setTokens(accessToken, expiresIn) {
29
+ this._accessToken = accessToken;
30
+ this._expiresAt = Date.now() + expiresIn * 1000;
31
+ this._scheduleRefresh(expiresIn);
32
+ }
33
+ /** Clear stored token and cancel any scheduled refresh. */
34
+ clear() {
35
+ this._accessToken = null;
36
+ this._expiresAt = 0;
37
+ this._cancelRefresh();
38
+ }
39
+ /**
40
+ * Refresh the access token via POST /refresh (using refresh cookie).
41
+ * Deduplicates concurrent calls — only one fetch in flight at a time.
42
+ */
43
+ async refresh() {
44
+ if (this._refreshPromise) {
45
+ return this._refreshPromise;
46
+ }
47
+ this._refreshPromise = this._doRefresh();
48
+ try {
49
+ return await this._refreshPromise;
50
+ }
51
+ finally {
52
+ this._refreshPromise = null;
53
+ }
54
+ }
55
+ /** Cleanup timers. */
56
+ dispose() {
57
+ this.clear();
58
+ }
59
+ // ---------------------------------------------------------------------------
60
+ // Private
61
+ // ---------------------------------------------------------------------------
62
+ async _doRefresh() {
63
+ try {
64
+ const response = await fetch(`${this._baseUrl}/refresh`, {
65
+ method: 'POST',
66
+ credentials: 'include',
67
+ headers: { 'Content-Type': 'application/json' },
68
+ body: JSON.stringify({}),
69
+ });
70
+ if (!response.ok) {
71
+ this.clear();
72
+ this._onRefreshFailure();
73
+ return null;
74
+ }
75
+ const data = await response.json();
76
+ this.setTokens(data.tokens.access_token, data.tokens.expires_in);
77
+ this._onRefreshSuccess(data);
78
+ return data;
79
+ }
80
+ catch {
81
+ this.clear();
82
+ this._onRefreshFailure();
83
+ return null;
84
+ }
85
+ }
86
+ _scheduleRefresh(expiresIn) {
87
+ this._cancelRefresh();
88
+ const refreshMs = (expiresIn - this._refreshBuffer) * 1000;
89
+ if (refreshMs > 0) {
90
+ this._refreshTimer = setTimeout(() => {
91
+ this.refresh();
92
+ }, refreshMs);
93
+ }
94
+ }
95
+ _cancelRefresh() {
96
+ if (this._refreshTimer !== null) {
97
+ clearTimeout(this._refreshTimer);
98
+ this._refreshTimer = null;
99
+ }
100
+ }
101
+ }
102
+ //# sourceMappingURL=token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../src/token-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,75 @@
1
+ /** Configuration for creating an AuthFort client. */
2
+ export interface AuthClientConfig {
3
+ /** Base URL of the auth server (e.g., "https://myapp.com/auth") */
4
+ baseUrl: string;
5
+ /**
6
+ * Token delivery mode.
7
+ * - `'cookie'` — server sets httponly cookies, JS never touches tokens (default)
8
+ * - `'bearer'` — access token stored in memory, sent via Authorization header
9
+ */
10
+ tokenMode?: 'cookie' | 'bearer';
11
+ /** Seconds before expiry to trigger proactive refresh (default: 30) */
12
+ refreshBuffer?: number;
13
+ }
14
+ /** Authentication state */
15
+ export type AuthState = 'authenticated' | 'unauthenticated' | 'loading';
16
+ /** Authenticated user data (camelCase) */
17
+ export interface AuthUser {
18
+ id: string;
19
+ email: string;
20
+ name?: string;
21
+ roles: string[];
22
+ emailVerified: boolean;
23
+ avatarUrl?: string;
24
+ createdAt: string;
25
+ }
26
+ /** Auth client interface */
27
+ export interface AuthClient {
28
+ /** Check for an existing session on app startup or after OAuth redirect. */
29
+ initialize(): Promise<void>;
30
+ /** Get a valid access token. Returns null in cookie mode. */
31
+ getToken(): Promise<string | null>;
32
+ /** Make an authenticated fetch request (auto-attaches token, handles 401 retry) */
33
+ fetch(url: string, options?: RequestInit): Promise<Response>;
34
+ /** Get current user data */
35
+ getUser(): Promise<AuthUser>;
36
+ /** Sign up with email and password */
37
+ signUp(data: {
38
+ email: string;
39
+ password: string;
40
+ name?: string;
41
+ }): Promise<AuthUser>;
42
+ /** Sign in with email and password */
43
+ signIn(data: {
44
+ email: string;
45
+ password: string;
46
+ }): Promise<AuthUser>;
47
+ /** Sign in with OAuth provider (redirects the browser) */
48
+ signInWithProvider(provider: string): void;
49
+ /** Sign out */
50
+ signOut(): Promise<void>;
51
+ /** Subscribe to auth state changes. Returns unsubscribe function. */
52
+ onAuthStateChange(callback: (state: AuthState, user: AuthUser | null) => void): () => void;
53
+ }
54
+ /** Token response from server */
55
+ export interface AuthTokens {
56
+ access_token: string;
57
+ refresh_token: string;
58
+ expires_in: number;
59
+ }
60
+ /** User response from server (snake_case) */
61
+ export interface ServerUserResponse {
62
+ id: string;
63
+ email: string;
64
+ name: string | null;
65
+ email_verified: boolean;
66
+ avatar_url: string | null;
67
+ roles: string[];
68
+ created_at: string;
69
+ }
70
+ /** Full auth response from server (signup/login/refresh) */
71
+ export interface ServerAuthResponse {
72
+ user: ServerUserResponse;
73
+ tokens: AuthTokens;
74
+ }
75
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAEhB;;;;OAIG;IACH,SAAS,CAAC,EAAE,QAAQ,GAAG,QAAQ,CAAC;IAEhC,uEAAuE;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,2BAA2B;AAC3B,MAAM,MAAM,SAAS,GAAG,eAAe,GAAG,iBAAiB,GAAG,SAAS,CAAC;AAExE,0CAA0C;AAC1C,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,4BAA4B;AAC5B,MAAM,WAAW,UAAU;IACzB,4EAA4E;IAC5E,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5B,6DAA6D;IAC7D,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAEnC,mFAAmF;IACnF,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE7D,4BAA4B;IAC5B,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE7B,sCAAsC;IACtC,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEpF,sCAAsC;IACtC,MAAM,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErE,0DAA0D;IAC1D,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IAE3C,eAAe;IACf,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEzB,qEAAqE;IACrE,iBAAiB,CACf,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,KAAK,IAAI,GAC1D,MAAM,IAAI,CAAC;CACf;AAMD,iCAAiC;AACjC,MAAM,WAAW,UAAU;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,6CAA6C;AAC7C,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,cAAc,EAAE,OAAO,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,4DAA4D;AAC5D,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,kBAAkB,CAAC;IACzB,MAAM,EAAE,UAAU,CAAC;CACpB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Vue composables for AuthFort.
3
+ *
4
+ * Usage:
5
+ * import { provideAuth, useAuth } from 'authfort-client/vue';
6
+ *
7
+ * // In root component setup
8
+ * provideAuth(auth);
9
+ *
10
+ * // In any child component
11
+ * const { user, isAuthenticated, client } = useAuth();
12
+ */
13
+ import { type Ref, type ComputedRef } from 'vue';
14
+ import type { AuthClient, AuthState, AuthUser } from '../types';
15
+ /** Provide the AuthFort client to all descendant components. Call in root component's setup. */
16
+ export declare function provideAuth(client: AuthClient): void;
17
+ /** Return type of useAuth() */
18
+ export interface UseAuthReturn {
19
+ /** Current auth state (readonly ref) */
20
+ state: Readonly<Ref<AuthState>>;
21
+ /** Current user (readonly ref, null when not authenticated) */
22
+ user: Readonly<Ref<AuthUser | null>>;
23
+ /** Whether the user is authenticated */
24
+ isAuthenticated: ComputedRef<boolean>;
25
+ /** Whether auth state is being determined */
26
+ isLoading: ComputedRef<boolean>;
27
+ /** The AuthFort client instance */
28
+ client: AuthClient;
29
+ }
30
+ /**
31
+ * Vue composable for AuthFort auth state.
32
+ * Must be called inside a component whose ancestor called provideAuth().
33
+ */
34
+ export declare function useAuth(): UseAuthReturn;
35
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAOL,KAAK,GAAG,EACR,KAAK,WAAW,EAEjB,MAAM,KAAK,CAAC;AACb,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAYhE,gGAAgG;AAChG,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAEpD;AAMD,+BAA+B;AAC/B,MAAM,WAAW,aAAa;IAC5B,wCAAwC;IACxC,KAAK,EAAE,QAAQ,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC;IAChC,+DAA+D;IAC/D,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAC;IACrC,wCAAwC;IACxC,eAAe,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IACtC,6CAA6C;IAC7C,SAAS,EAAE,WAAW,CAAC,OAAO,CAAC,CAAC;IAChC,mCAAmC;IACnC,MAAM,EAAE,UAAU,CAAC;CACpB;AAED;;;GAGG;AACH,wBAAgB,OAAO,IAAI,aAAa,CAuBvC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Vue composables for AuthFort.
3
+ *
4
+ * Usage:
5
+ * import { provideAuth, useAuth } from 'authfort-client/vue';
6
+ *
7
+ * // In root component setup
8
+ * provideAuth(auth);
9
+ *
10
+ * // In any child component
11
+ * const { user, isAuthenticated, client } = useAuth();
12
+ */
13
+ import { ref, readonly, computed, inject, provide, onUnmounted, } from 'vue';
14
+ // ---------------------------------------------------------------------------
15
+ // Injection key
16
+ // ---------------------------------------------------------------------------
17
+ const AUTH_KEY = Symbol('authfort');
18
+ // ---------------------------------------------------------------------------
19
+ // Provider
20
+ // ---------------------------------------------------------------------------
21
+ /** Provide the AuthFort client to all descendant components. Call in root component's setup. */
22
+ export function provideAuth(client) {
23
+ provide(AUTH_KEY, client);
24
+ }
25
+ /**
26
+ * Vue composable for AuthFort auth state.
27
+ * Must be called inside a component whose ancestor called provideAuth().
28
+ */
29
+ export function useAuth() {
30
+ const client = inject(AUTH_KEY);
31
+ if (!client) {
32
+ throw new Error('useAuth() requires provideAuth() in a parent component');
33
+ }
34
+ const state = ref('unauthenticated');
35
+ const user = ref(null);
36
+ const unsubscribe = client.onAuthStateChange((s, u) => {
37
+ state.value = s;
38
+ user.value = u;
39
+ });
40
+ onUnmounted(unsubscribe);
41
+ return {
42
+ state: readonly(state),
43
+ user: readonly(user),
44
+ isAuthenticated: computed(() => state.value === 'authenticated'),
45
+ isLoading: computed(() => state.value === 'loading'),
46
+ client,
47
+ };
48
+ }
49
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,GAAG,EACH,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,OAAO,EACP,WAAW,GAIZ,MAAM,KAAK,CAAC;AAGb,8EAA8E;AAC9E,gBAAgB;AAChB,8EAA8E;AAE9E,MAAM,QAAQ,GAA6B,MAAM,CAAC,UAAU,CAAC,CAAC;AAE9D,8EAA8E;AAC9E,WAAW;AACX,8EAA8E;AAE9E,gGAAgG;AAChG,MAAM,UAAU,WAAW,CAAC,MAAkB;IAC5C,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;AAC5B,CAAC;AAoBD;;;GAGG;AACH,MAAM,UAAU,OAAO;IACrB,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC;IAChC,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAC;IAC5E,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAY,iBAAiB,CAAC,CAAC;IAChD,MAAM,IAAI,GAAG,GAAG,CAAkB,IAAI,CAAC,CAAC;IAExC,MAAM,WAAW,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QACpD,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC;QAChB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;IAEH,WAAW,CAAC,WAAW,CAAC,CAAC;IAEzB,OAAO;QACL,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC;QACtB,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAmC;QACtD,eAAe,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,eAAe,CAAC;QAChE,SAAS,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,KAAK,KAAK,SAAS,CAAC;QACpD,MAAM;KACP,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "authfort-client",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "TypeScript client SDK for AuthFort authentication",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
+ "files": ["dist"],
8
9
  "exports": {
9
10
  ".": {
10
11
  "import": "./dist/index.js",
@@ -25,12 +26,37 @@
25
26
  },
26
27
  "scripts": {
27
28
  "build": "tsc",
28
- "dev": "tsc --watch"
29
+ "dev": "tsc --watch",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest"
32
+ },
33
+ "peerDependencies": {
34
+ "react": ">=18",
35
+ "vue": ">=3",
36
+ "svelte": ">=4"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "react": { "optional": true },
40
+ "vue": { "optional": true },
41
+ "svelte": { "optional": true }
42
+ },
43
+ "keywords": ["auth", "authentication", "jwt", "oauth", "typescript"],
44
+ "author": "Bhagyajit Jagdev",
45
+ "license": "MIT",
46
+ "repository": {
47
+ "type": "git",
48
+ "url": "https://github.com/bhagyajitjagdev/authfort"
29
49
  },
30
- "keywords": [],
31
- "author": "",
32
- "license": "ISC",
33
50
  "devDependencies": {
34
- "typescript": "^5.9.3"
51
+ "@testing-library/react": "^16.3.2",
52
+ "@types/react": "^19.2.14",
53
+ "@vue/test-utils": "^2.4.6",
54
+ "jsdom": "^28.1.0",
55
+ "react": "^19.2.4",
56
+ "react-dom": "^19.2.4",
57
+ "svelte": "^5.51.3",
58
+ "typescript": "^5.9.3",
59
+ "vitest": "^4.0.18",
60
+ "vue": "^3.5.28"
35
61
  }
36
62
  }
package/CLAUDE.md DELETED
@@ -1,45 +0,0 @@
1
- # AuthFort Client — AI Reference
2
-
3
- ## Commands (User Runs These)
4
-
5
- ```bash
6
- # Install dependencies
7
- npm install
8
-
9
- # Build
10
- npm run build
11
-
12
- # Watch mode
13
- npm run dev
14
- ```
15
-
16
- ## Structure
17
-
18
- ```
19
- client/
20
- ├── package.json
21
- ├── tsconfig.json
22
- └── src/
23
- ├── index.ts # Public API exports
24
- ├── types.ts # TypeScript interfaces
25
- ├── client.ts # createAuthClient factory
26
- ├── token-manager.ts # Token lifecycle (refresh, dedup)
27
- ├── react/index.ts # React hooks (useAuth)
28
- ├── vue/index.ts # Vue composables
29
- └── svelte/index.ts # Svelte stores
30
- ```
31
-
32
- ## Purpose
33
-
34
- TypeScript SDK for frontend apps. Handles:
35
- - Token storage and retrieval
36
- - Proactive refresh (30s before expiry)
37
- - Refresh promise deduplication (concurrent calls share one refresh)
38
- - 401 retry (for immediate role invalidation)
39
- - Auth state management (authenticated/unauthenticated/loading)
40
-
41
- ## Constraints
42
-
43
- - **No server-side code** — this is a client-side SDK
44
- - **Framework-agnostic core** — React/Vue/Svelte are optional exports
45
- - **Never store tokens insecurely** — httponly cookies for web, secure storage guidance for mobile
package/src/client.ts DELETED
@@ -1,10 +0,0 @@
1
- /**
2
- * AuthFort client factory — creates an auth client instance.
3
- */
4
-
5
- import type { AuthClientConfig, AuthClient } from './types';
6
-
7
- export function createAuthClient(_config: AuthClientConfig): AuthClient {
8
- // TODO: Implement in Phase 4
9
- throw new Error('Not yet implemented');
10
- }
@@ -1,5 +0,0 @@
1
- /**
2
- * React hooks for AuthFort.
3
- *
4
- * Provides useAuth() and useSession() hooks.
5
- */
@@ -1,3 +0,0 @@
1
- /**
2
- * Svelte stores for AuthFort.
3
- */
@@ -1,8 +0,0 @@
1
- /**
2
- * Token lifecycle manager.
3
- *
4
- * Handles:
5
- * - Proactive refresh (before expiry)
6
- * - Single refresh promise deduplication
7
- * - Token storage
8
- */
package/src/types.ts DELETED
@@ -1,51 +0,0 @@
1
- /** Configuration for creating an AuthFort client. */
2
- export interface AuthClientConfig {
3
- /** Base URL of the auth server (e.g., "https://myapp.com/auth") */
4
- baseUrl: string;
5
-
6
- /** Token delivery mode */
7
- tokenMode?: 'cookie' | 'bearer' | 'both';
8
-
9
- /** Seconds before expiry to trigger proactive refresh (default: 30) */
10
- refreshBuffer?: number;
11
- }
12
-
13
- /** Authentication state */
14
- export type AuthState = 'authenticated' | 'unauthenticated' | 'loading';
15
-
16
- /** Authenticated user data */
17
- export interface AuthUser {
18
- id: string;
19
- email: string;
20
- name?: string;
21
- roles: string[];
22
- emailVerified: boolean;
23
- avatarUrl?: string;
24
- }
25
-
26
- /** Auth client interface */
27
- export interface AuthClient {
28
- /** Get a valid access token (refreshes if needed) */
29
- getToken(): Promise<string>;
30
-
31
- /** Make an authenticated fetch request (auto-attaches token, handles 401 retry) */
32
- fetch(url: string, options?: RequestInit): Promise<Response>;
33
-
34
- /** Get current user data */
35
- getUser(): Promise<AuthUser>;
36
-
37
- /** Sign up with email and password */
38
- signUp(data: { email: string; password: string; name?: string }): Promise<AuthUser>;
39
-
40
- /** Sign in with email and password */
41
- signIn(data: { email: string; password: string }): Promise<AuthUser>;
42
-
43
- /** Sign in with OAuth provider (redirects) */
44
- signInWithProvider(provider: string): void;
45
-
46
- /** Sign out */
47
- signOut(): Promise<void>;
48
-
49
- /** Subscribe to auth state changes */
50
- onAuthStateChange(callback: (state: AuthState) => void): () => void;
51
- }
package/src/vue/index.ts DELETED
@@ -1,5 +0,0 @@
1
- /**
2
- * Vue composables for AuthFort.
3
- *
4
- * Provides useAuth() and useSession() composables.
5
- */
package/tsconfig.json DELETED
@@ -1,21 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ESNext",
5
- "moduleResolution": "bundler",
6
- "lib": ["ES2020", "DOM"],
7
- "outDir": "dist",
8
- "rootDir": "src",
9
- "declaration": true,
10
- "declarationMap": true,
11
- "sourceMap": true,
12
- "strict": true,
13
- "esModuleInterop": true,
14
- "skipLibCheck": true,
15
- "forceConsistentCasingInFileNames": true,
16
- "isolatedModules": true,
17
- "jsx": "react-jsx"
18
- },
19
- "include": ["src"],
20
- "exclude": ["node_modules", "dist"]
21
- }