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 +141 -0
- package/dist/client.d.ts +7 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +236 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +24 -0
- package/dist/errors.js.map +1 -0
- package/{src/index.ts → dist/index.d.ts} +2 -1
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +40 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +48 -0
- package/dist/react/index.js.map +1 -0
- package/dist/svelte/index.d.ts +34 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +34 -0
- package/dist/svelte/index.js.map +1 -0
- package/dist/token-manager.d.ts +37 -0
- package/dist/token-manager.d.ts.map +1 -0
- package/dist/token-manager.js +102 -0
- package/dist/token-manager.js.map +1 -0
- package/dist/types.d.ts +75 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/vue/index.d.ts +35 -0
- package/dist/vue/index.d.ts.map +1 -0
- package/dist/vue/index.js +49 -0
- package/dist/vue/index.js.map +1 -0
- package/package.json +32 -6
- package/CLAUDE.md +0 -45
- package/src/client.ts +0 -10
- package/src/react/index.ts +0 -5
- package/src/svelte/index.ts +0 -3
- package/src/token-manager.ts +0 -8
- package/src/types.ts +0 -51
- package/src/vue/index.ts +0 -5
- package/tsconfig.json +0 -21
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)
|
package/dist/client.d.ts
ADDED
|
@@ -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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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -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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"}
|
package/dist/types.d.ts
ADDED
|
@@ -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 @@
|
|
|
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.
|
|
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
|
-
"
|
|
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
|
-
}
|
package/src/react/index.ts
DELETED
package/src/svelte/index.ts
DELETED
package/src/token-manager.ts
DELETED
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
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
|
-
}
|