@jasperoosthoek/zustand-auth-registry 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 jasperoosthoek
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,407 @@
1
+ # zustand-auth-registry
2
+
3
+ OAuth 2.0 compliant authentication state management library using Zustand and Axios with a type-safe registry pattern.
4
+
5
+ ## Overview
6
+
7
+ `zustand-auth-registry` provides a simple, type-safe way to manage authentication state in React applications using Zustand. It supports both modern OAuth 2.0 standards and legacy authentication patterns, with automatic token refresh, Bearer token support, and comprehensive backward compatibility.
8
+
9
+ ## Features
10
+
11
+ - **OAuth 2.0 Compliance** - Industry-standard Bearer tokens, automatic refresh, token lifecycle management
12
+ - **Authentication State Management** - User, token, and authentication status with reactive updates
13
+ - **Registry Pattern** - Type-safe multiple auth stores per application
14
+ - **Axios Integration** - Automatic authentication header management with configurable formats
15
+ - **Token Lifecycle** - Automatic expiration detection, refresh workflows, and cleanup
16
+ - **Auto-Refresh** - Configurable threshold-based token renewal (default: 5 minutes before expiry)
17
+ - **Persistence** - Flexible storage options (localStorage, sessionStorage, custom) with OAuth token support
18
+ - **Type-Safe** - Full TypeScript support with generics for user models
19
+ - **Backward Compatible** - Seamless support for Django REST Framework and legacy APIs
20
+ - **Flexible** - Support for multiple APIs with different authentication strategies
21
+ - **Lightweight** - Simple API, no unnecessary complexity
22
+
23
+ ## Installation
24
+
25
+ ```bash
26
+ npm install @jasperoosthoek/zustand-auth-registry zustand axios react
27
+ ```
28
+
29
+ ## Quick Start
30
+
31
+ ### OAuth 2.0 Setup (Recommended)
32
+
33
+ ```typescript
34
+ import axios from 'axios';
35
+ import { createAuthRegistry, useAuth } from '@jasperoosthoek/zustand-auth-registry';
36
+
37
+ // 1. Define your user type
38
+ type User = {
39
+ id: string;
40
+ email: string;
41
+ name: string;
42
+ };
43
+
44
+ // 2. Create registry
45
+ const getAuthStore = createAuthRegistry<{
46
+ main: User;
47
+ }>();
48
+
49
+ // 3. Create axios instance
50
+ const api = axios.create({ baseURL: 'https://api.example.com' });
51
+
52
+ // 4. Create OAuth 2.0 compliant auth store
53
+ export const authStore = getAuthStore('main', {
54
+ axios: api,
55
+ tokenUrl: '/oauth/token',
56
+ userInfoUrl: '/oauth/userinfo',
57
+ // Automatic OAuth token extraction (access_token, refresh_token, expires_in)
58
+ // Automatic Bearer header format
59
+ // Auto-refresh enabled by default
60
+ });
61
+
62
+ // 5. Use in components
63
+ function LoginForm() {
64
+ const { login } = useAuth(authStore);
65
+ const { user, isAuthenticated } = authStore((s) => s);
66
+
67
+ const handleLogin = async () => {
68
+ await login({
69
+ username: 'user@example.com',
70
+ password: 'password'
71
+ });
72
+ };
73
+
74
+ if (isAuthenticated) {
75
+ return <div>Welcome {user?.name}!</div>;
76
+ }
77
+
78
+ return <button onClick={handleLogin}>Login</button>;
79
+ }
80
+ ```
81
+
82
+ ### Legacy/Django Setup (Backward Compatible)
83
+
84
+ ```typescript
85
+ // Works with existing Django REST Framework patterns
86
+ export const authStore = getAuthStore('main', {
87
+ axios: api,
88
+ loginUrl: '/api/token/login/', // Legacy endpoint
89
+ logoutUrl: '/api/token/logout/',
90
+ getUserUrl: '/api/users/me/',
91
+ extractToken: (data) => data.auth_token, // Django field name
92
+ formatAuthHeader: (token) => `Token ${token}`, // Django format
93
+ });
94
+ ```
95
+
96
+ ## Use Cases
97
+
98
+ ### OAuth 2.0 Provider Integration
99
+
100
+ ```typescript
101
+ // Works with Auth0, Google, GitHub, or any OAuth 2.0 provider
102
+ const auth0Store = getAuthStore('auth0', {
103
+ axios: api,
104
+ tokenUrl: 'https://your-domain.auth0.com/oauth/token',
105
+ userInfoUrl: 'https://your-domain.auth0.com/userinfo',
106
+ autoRefresh: true,
107
+ refreshThreshold: 300000, // Refresh 5 minutes before expiry
108
+ onTokenRefresh: (tokens) => {
109
+ console.log('Token refreshed, expires at:', new Date(tokens.expiresAt));
110
+ }
111
+ });
112
+ ```
113
+
114
+ ### JWT Token Support
115
+
116
+ ```typescript
117
+ // Automatic JWT expiration detection
118
+ const jwtStore = getAuthStore('jwt', {
119
+ axios: api,
120
+ tokenUrl: '/api/auth/login',
121
+ extractTokens: (data) => {
122
+ const payload = JSON.parse(atob(data.access_token.split('.')[1]));
123
+ return {
124
+ accessToken: data.access_token,
125
+ expiresAt: payload.exp * 1000, // JWT exp is in seconds
126
+ tokenType: 'Bearer'
127
+ };
128
+ }
129
+ });
130
+ ```
131
+
132
+ ### Multiple APIs with Different Authentication
133
+
134
+ ```typescript
135
+ const internalApi = axios.create({ baseURL: 'https://internal.app.com' });
136
+ const partnerApi = axios.create({ baseURL: 'https://partner.api.com' });
137
+
138
+ // Internal API uses legacy Token authentication
139
+ const internalAuth = getAuthStore('internal', {
140
+ axios: internalApi,
141
+ loginUrl: '/api/token/login/',
142
+ extractToken: (data) => data.auth_token,
143
+ formatAuthHeader: (token) => `Token ${token}`,
144
+ });
145
+
146
+ // Partner API uses OAuth 2.0 Bearer authentication
147
+ const partnerAuth = getAuthStore('partner', {
148
+ axios: partnerApi,
149
+ tokenUrl: '/oauth/token',
150
+ userInfoUrl: '/oauth/userinfo',
151
+ // Uses Bearer tokens and auto-refresh by default
152
+ });
153
+ ```
154
+
155
+ ### Custom Storage Configuration
156
+
157
+ ```typescript
158
+ const authStore = getAuthStore('main', {
159
+ axios: api,
160
+ tokenUrl: '/oauth/token',
161
+ persistence: {
162
+ enabled: true,
163
+ storage: sessionStorage, // Use sessionStorage instead of localStorage
164
+ tokenKey: 'access_token', // OAuth standard (default)
165
+ refreshTokenKey: 'refresh_token',
166
+ userKey: 'user_profile',
167
+ expiryKey: 'token_expires_at',
168
+ },
169
+ });
170
+ ```
171
+
172
+ ### SSR/No Persistence
173
+
174
+ ```typescript
175
+ const authStore = getAuthStore('main', {
176
+ axios: api,
177
+ tokenUrl: '/oauth/token',
178
+ persistence: {
179
+ enabled: false, // Disable persistence for SSR
180
+ },
181
+ });
182
+ ```
183
+
184
+ ## Integration with zustand-crud-registry
185
+
186
+ Works seamlessly with [@jasperoosthoek/zustand-crud-registry](https://github.com/jasperoosthoek/zustand-crud-registry):
187
+
188
+ ```typescript
189
+ import { createStoreRegistry } from '@jasperoosthoek/zustand-crud-registry';
190
+ import { createAuthRegistry } from '@jasperoosthoek/zustand-auth-registry';
191
+
192
+ // Shared axios instance
193
+ const api = axios.create({ baseURL: 'https://api.example.com' });
194
+
195
+ // Auth manages authentication with auto-refresh
196
+ const auth = getAuthStore('main', {
197
+ axios: api,
198
+ tokenUrl: '/oauth/token',
199
+ autoRefresh: true
200
+ });
201
+
202
+ // CRUD uses the same authenticated axios
203
+ const getCrudStore = createStoreRegistry<{ user: User; post: Post }>();
204
+ const users = getCrudStore('user', { axios: api, route: '/users' });
205
+
206
+ // Login first, then use CRUD
207
+ const { login } = useAuth(auth);
208
+ const { list, getList } = useCrud(users);
209
+
210
+ await login({ username: '...', password: '...' });
211
+ await getList(); // Authenticated request with auto-refreshed tokens
212
+ ```
213
+
214
+ ## API Reference
215
+
216
+ ### `createAuthRegistry<Models>()`
217
+
218
+ Creates a registry function for type-safe auth stores.
219
+
220
+ ```typescript
221
+ type Models = {
222
+ main: MainUser;
223
+ admin: AdminUser;
224
+ };
225
+
226
+ const getAuthStore = createAuthRegistry<Models>();
227
+ ```
228
+
229
+ ### `getAuthStore(key, config)`
230
+
231
+ Creates or retrieves an auth store.
232
+
233
+ **Parameters:**
234
+ - `key`: Unique identifier for the store
235
+ - `config`: Authentication configuration
236
+
237
+ **Returns:** Auth store with Zustand state and config metadata
238
+
239
+ ### `AuthConfig<U>`
240
+
241
+ Configuration object for authentication.
242
+
243
+ ```typescript
244
+ type AuthConfig<U> = {
245
+ // Required
246
+ axios: AxiosInstance;
247
+
248
+ // OAuth 2.0 endpoints (recommended)
249
+ tokenUrl?: string; // POST /oauth/token
250
+ revokeUrl?: string; // POST /oauth/revoke
251
+ userInfoUrl?: string; // GET /oauth/userinfo
252
+
253
+ // Legacy endpoints (backward compatibility)
254
+ loginUrl?: string; // POST /api/token/login/
255
+ logoutUrl?: string; // POST /api/token/logout/
256
+ getUserUrl?: string; // GET /api/users/me/
257
+
258
+ // OAuth 2.0 token extraction (automatic if not specified)
259
+ extractTokens?: (data: any) => TokenData;
260
+
261
+ // Legacy token extraction (backward compatibility)
262
+ extractToken?: (data: any) => string;
263
+
264
+ // Token formatting (defaults to Bearer)
265
+ formatAuthHeader?: (token: string, tokenType?: string) => string;
266
+
267
+ // OAuth 2.0 features
268
+ autoRefresh?: boolean; // Default: true
269
+ refreshThreshold?: number; // Default: 300000ms (5 minutes)
270
+
271
+ // Storage configuration
272
+ persistence?: {
273
+ enabled?: boolean; // Default: true
274
+ storage?: Storage; // Default: localStorage
275
+ tokenKey?: string; // Default: 'token'
276
+ refreshTokenKey?: string; // Default: 'refresh_token'
277
+ userKey?: string; // Default: 'user'
278
+ expiryKey?: string; // Default: 'expires_at'
279
+ };
280
+
281
+ // Event callbacks
282
+ onError?: (error: any) => void;
283
+ onLogin?: (user: U) => void;
284
+ onLogout?: () => void;
285
+ onTokenRefresh?: (tokens: TokenData) => void;
286
+ };
287
+ ```
288
+
289
+ ### `TokenData`
290
+
291
+ OAuth 2.0 compliant token structure.
292
+
293
+ ```typescript
294
+ type TokenData = {
295
+ accessToken: string; // OAuth 2.0 standard
296
+ refreshToken?: string; // For token renewal
297
+ expiresAt?: number; // Timestamp for expiration
298
+ tokenType: string; // 'Bearer' (default) or custom
299
+ scope?: string[]; // OAuth scope support
300
+ };
301
+ ```
302
+
303
+ ### `useAuth(store)`
304
+
305
+ React hook for authentication actions.
306
+
307
+ **Returns:**
308
+ ```typescript
309
+ {
310
+ login: (credentials: Record<string, string>, callback?: () => void) => Promise<void>;
311
+ logout: () => Promise<void>;
312
+ getCurrentUser: () => Promise<void>;
313
+ refreshTokens: () => Promise<boolean>; // OAuth 2.0 token refresh
314
+ }
315
+ ```
316
+
317
+ ### Auth Store State
318
+
319
+ Access auth state using the store:
320
+
321
+ ```typescript
322
+ const { user, token, tokens, isAuthenticated } = authStore((s) => s);
323
+ ```
324
+
325
+ **State:**
326
+ - `user: U | null` - Current user object
327
+ - `token: string` - Authentication token (backward compatibility)
328
+ - `tokens: TokenData | null` - OAuth 2.0 token structure
329
+ - `isAuthenticated: boolean` - Whether user is authenticated (based on valid token)
330
+
331
+ **Actions:**
332
+ - `setToken(token: string)` - Set authentication token (backward compatibility)
333
+ - `setTokens(tokens: TokenData)` - Set OAuth 2.0 tokens
334
+ - `setUser(user: U)` - Set user object
335
+ - `unsetUser()` - Clear user and tokens (logout)
336
+ - `isTokenExpired(): boolean` - Check if current token is expired
337
+
338
+ ## Migration Guide
339
+
340
+ ### From Legacy to OAuth 2.0
341
+
342
+ **Step 1: No changes required (existing code continues to work)**
343
+ ```typescript
344
+ // Existing configurations work unchanged
345
+ const authStore = getAuthStore('main', {
346
+ loginUrl: '/api/token/login/',
347
+ extractToken: (data) => data.auth_token,
348
+ formatAuthHeader: (token) => `Token ${token}`
349
+ });
350
+ ```
351
+
352
+ **Step 2: Gradual OAuth adoption**
353
+ ```typescript
354
+ // Start using OAuth endpoints while keeping legacy token extraction
355
+ const authStore = getAuthStore('main', {
356
+ tokenUrl: '/oauth/token', // OAuth endpoint
357
+ extractToken: (data) => data.auth_token, // Legacy extraction
358
+ formatAuthHeader: (token) => `Token ${token}` // Legacy headers
359
+ });
360
+ ```
361
+
362
+ **Step 3: Full OAuth 2.0**
363
+ ```typescript
364
+ // Complete OAuth 2.0 implementation
365
+ const authStore = getAuthStore('main', {
366
+ tokenUrl: '/oauth/token',
367
+ revokeUrl: '/oauth/revoke',
368
+ userInfoUrl: '/oauth/userinfo',
369
+ // OAuth token extraction and Bearer headers are automatic
370
+ autoRefresh: true,
371
+ refreshThreshold: 300000 // 5 minutes
372
+ });
373
+ ```
374
+
375
+ ## Development
376
+
377
+ See [SETUP.md](./SETUP.md) for detailed setup and development instructions.
378
+
379
+ ```bash
380
+ # Install dependencies
381
+ npm install
382
+
383
+ # Build
384
+ npm run build
385
+
386
+ # Test (67 tests, 100% pass rate)
387
+ npm test
388
+
389
+ # Coverage
390
+ npm run test:coverage
391
+ ```
392
+
393
+ ## OAuth 2.0 Compliance
394
+
395
+ This library implements OAuth 2.0 (RFC 6749) standards with Bearer Token Authentication (RFC 6750), token refresh flows, proper token lifecycle management, and standard field names. For detailed implementation information and future roadmap, see [docs/OAUTH_ROADMAP.md](./docs/OAUTH_ROADMAP.md).
396
+
397
+ ## Related Projects
398
+
399
+ - [@jasperoosthoek/zustand-crud-registry](https://github.com/jasperoosthoek/zustand-crud-registry) - CRUD operations for REST APIs
400
+
401
+ ## License
402
+
403
+ MIT
404
+
405
+ ## Author
406
+
407
+ Jasper Oosthoek
@@ -0,0 +1,67 @@
1
+ import { AxiosInstance } from 'axios';
2
+ export type TokenData = {
3
+ accessToken: string;
4
+ refreshToken?: string;
5
+ expiresAt?: number;
6
+ tokenType: string;
7
+ scope?: string[];
8
+ };
9
+ export type TokenExtractor = (data: any) => string | TokenData;
10
+ export type AuthConfig<U> = {
11
+ axios: AxiosInstance;
12
+ tokenUrl?: string;
13
+ revokeUrl?: string;
14
+ userInfoUrl?: string;
15
+ loginUrl?: string;
16
+ logoutUrl?: string;
17
+ getUserUrl?: string;
18
+ extractTokens?: (data: any) => TokenData;
19
+ extractAccessToken?: (data: any) => string;
20
+ extractRefreshToken?: (data: any) => string | undefined;
21
+ extractExpiresIn?: (data: any) => number | undefined;
22
+ extractTokenType?: (data: any) => string;
23
+ extractScope?: (data: any) => string[] | undefined;
24
+ extractToken?: (data: any) => string;
25
+ formatAuthHeader?: (token: string, tokenType?: string) => string;
26
+ autoRefresh?: boolean;
27
+ refreshThreshold?: number;
28
+ persistence?: {
29
+ enabled?: boolean;
30
+ storage?: Storage;
31
+ tokenKey?: string;
32
+ refreshTokenKey?: string;
33
+ userKey?: string;
34
+ expiryKey?: string;
35
+ };
36
+ onError?: (error: any) => void;
37
+ onLogin?: (user: U) => void;
38
+ onLogout?: () => void;
39
+ onTokenRefresh?: (tokens: TokenData) => void;
40
+ };
41
+ export type ValidatedAuthConfig<U> = {
42
+ axios: AxiosInstance;
43
+ tokenUrl: string;
44
+ revokeUrl?: string;
45
+ userInfoUrl?: string;
46
+ loginUrl?: string;
47
+ logoutUrl?: string;
48
+ getUserUrl?: string;
49
+ extractTokens: (data: any) => TokenData;
50
+ extractToken?: (data: any) => string;
51
+ formatAuthHeader: (token: string, tokenType?: string) => string;
52
+ autoRefresh: boolean;
53
+ refreshThreshold: number;
54
+ persistence: {
55
+ enabled: boolean;
56
+ storage: Storage;
57
+ tokenKey: string;
58
+ refreshTokenKey: string;
59
+ userKey: string;
60
+ expiryKey: string;
61
+ };
62
+ onError?: (error: any) => void;
63
+ onLogin?: (user: U) => void;
64
+ onLogout?: () => void;
65
+ onTokenRefresh?: (tokens: TokenData) => void;
66
+ };
67
+ export declare const validateAuthConfig: <U>(config: AuthConfig<U>) => ValidatedAuthConfig<U>;
@@ -0,0 +1,17 @@
1
+ import { StoreApi, UseBoundStore } from 'zustand';
2
+ import { ValidatedAuthConfig, TokenData } from './authConfig';
3
+ export type AuthState<U> = {
4
+ isAuthenticated: boolean;
5
+ user: U | null;
6
+ tokens: TokenData | null;
7
+ setTokens: (tokens: TokenData) => void;
8
+ setUser: (user: U) => void;
9
+ unsetUser: () => void;
10
+ isTokenExpired: () => boolean;
11
+ token: string;
12
+ setToken: (token: string) => void;
13
+ };
14
+ export type AuthStore<U> = UseBoundStore<StoreApi<AuthState<U>>> & {
15
+ config: ValidatedAuthConfig<U>;
16
+ };
17
+ export declare const createAuthStore: <U>(config: ValidatedAuthConfig<U>) => AuthStore<U>;
@@ -0,0 +1,3 @@
1
+ import { AuthConfig } from './authConfig';
2
+ import { AuthStore } from './authStore';
3
+ export declare function createAuthRegistry<AuthModels extends Record<string, any>>(): <K extends keyof AuthModels>(key: K, config: AuthConfig<AuthModels[K]>) => AuthStore<AuthModels[K]>;
@@ -0,0 +1,4 @@
1
+ export * from './authConfig';
2
+ export * from './authStore';
3
+ export * from './createAuthRegistry';
4
+ export * from './useAuth';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ !function(e,r){"object"==typeof exports&&"object"==typeof module?module.exports=r(require("zustand"),require("react"),require("axios")):"function"==typeof define&&define.amd?define(["zustand","react","axios"],r):"object"==typeof exports?exports["@jasperoosthoek/zustand-auth-registry"]=r(require("zustand"),require("react"),require("axios")):e["@jasperoosthoek/zustand-auth-registry"]=r(e.zustand,e.react,e.axios)}(this,(e,r,t)=>(()=>{"use strict";var n={155:e=>{e.exports=r},287:r=>{r.exports=e},742:e=>{e.exports=t}},o={};function s(e){var r=o[e];if(void 0!==r)return r.exports;var t=o[e]={exports:{}};return n[e](t,t.exports,s),t.exports}s.n=e=>{var r=e&&e.__esModule?()=>e.default:()=>e;return s.d(r,{a:r}),r},s.d=(e,r)=>{for(var t in r)s.o(r,t)&&!s.o(e,t)&&Object.defineProperty(e,t,{enumerable:!0,get:r[t]})},s.o=(e,r)=>Object.prototype.hasOwnProperty.call(e,r),s.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var a={};s.r(a),s.d(a,{createAuthRegistry:()=>f,createAuthStore:()=>l,useAuth:()=>y,validateAuthConfig:()=>u});var i=function(){return i=Object.assign||function(e){for(var r,t=1,n=arguments.length;t<n;t++)for(var o in r=arguments[t])Object.prototype.hasOwnProperty.call(r,o)&&(e[o]=r[o]);return e},i.apply(this,arguments)},u=function(e){var r,t;if(!e.axios)throw new Error("AuthConfig: axios instance is required");var n=e.tokenUrl||e.loginUrl;if(!n)throw new Error("AuthConfig: tokenUrl or loginUrl is required");var o=e.revokeUrl,s=e.userInfoUrl||e.getUserUrl,a=function(e){return function(r){if(e.extractTokens)return e.extractTokens(r);if(r.access_token)return{accessToken:e.extractAccessToken?e.extractAccessToken(r):r.access_token,refreshToken:e.extractRefreshToken?e.extractRefreshToken(r):r.refresh_token,expiresAt:e.extractExpiresIn?e.extractExpiresIn(r)?Date.now()+1e3*e.extractExpiresIn(r):void 0:r.expires_in?Date.now()+1e3*r.expires_in:void 0,tokenType:e.extractTokenType?e.extractTokenType(r):r.token_type||"Bearer",scope:e.extractScope?e.extractScope(r):r.scope?r.scope.split(" "):void 0};if(e.extractToken||r.auth_token||r.token)return{accessToken:e.extractToken?e.extractToken(r):r.auth_token||r.token,tokenType:"Bearer"};throw new Error("No valid token found in response. Provide extractTokens, extractToken, or ensure response contains access_token/auth_token field.")}}(e),u={enabled:!0,storage:"undefined"!=typeof window&&window.localStorage?window.localStorage:{},tokenKey:"token",refreshTokenKey:"refresh_token",userKey:"user",expiryKey:"expires_at"};return{axios:e.axios,tokenUrl:n,revokeUrl:o,userInfoUrl:s,loginUrl:e.loginUrl,logoutUrl:e.logoutUrl,getUserUrl:e.getUserUrl,extractTokens:a,extractToken:e.extractToken,formatAuthHeader:e.formatAuthHeader||function(e,r){return void 0===r&&(r="Bearer"),"".concat(r," ").concat(e)},autoRefresh:null===(r=e.autoRefresh)||void 0===r||r,refreshThreshold:null!==(t=e.refreshThreshold)&&void 0!==t?t:3e5,persistence:i(i({},u),e.persistence),onError:e.onError,onLogin:e.onLogin,onLogout:e.onLogout,onTokenRefresh:e.onTokenRefresh}},c=s(287),l=function(e){var r=e.persistence,t=function(){if(!r.enabled)return null;try{var e=r.storage.getItem(r.tokenKey);if(!e)return null;var t=r.storage.getItem(r.refreshTokenKey),n=r.storage.getItem(r.expiryKey),o=n?parseInt(n,10):void 0;return{accessToken:e,refreshToken:t||void 0,expiresAt:o&&!isNaN(o)?o:void 0,tokenType:"Bearer"}}catch(e){return null}}(),n=function(){if(!r.enabled)return null;try{var e=r.storage.getItem(r.userKey);return e?JSON.parse(e):null}catch(e){return null}}(),o=!!(null==t?void 0:t.accessToken),s=(0,c.create)(function(s,a){return{tokens:t,user:n,isAuthenticated:o,setTokens:function(t){a().user;var n,o=!!t.accessToken;if(s({tokens:t,isAuthenticated:o,token:t.accessToken}),r.enabled)try{r.storage.setItem(r.tokenKey,t.accessToken),t.refreshToken?r.storage.setItem(r.refreshTokenKey,t.refreshToken):r.storage.removeItem(r.refreshTokenKey),t.expiresAt?r.storage.setItem(r.expiryKey,t.expiresAt.toString()):r.storage.removeItem(r.expiryKey)}catch(r){null===(n=e.onError)||void 0===n||n.call(e,r)}},setUser:function(t){var n,o=a().tokens,i=!!(null==o?void 0:o.accessToken);if(s({user:t,isAuthenticated:i}),r.enabled)try{r.storage.setItem(r.userKey,JSON.stringify(t))}catch(r){null===(n=e.onError)||void 0===n||n.call(e,r)}},unsetUser:function(){var t;if(s({user:null,tokens:null,isAuthenticated:!1,token:""}),r.enabled)try{r.storage.removeItem(r.tokenKey),r.storage.removeItem(r.refreshTokenKey),r.storage.removeItem(r.userKey),r.storage.removeItem(r.expiryKey)}catch(r){null===(t=e.onError)||void 0===t||t.call(e,r)}},isTokenExpired:function(){var e=a().tokens;return!!(null==e?void 0:e.expiresAt)&&Date.now()>=e.expiresAt},token:(null==t?void 0:t.accessToken)||"",setToken:function(t){var n,o=a().tokens,i=(a().user,{accessToken:t,refreshToken:null==o?void 0:o.refreshToken,expiresAt:null==o?void 0:o.expiresAt,tokenType:(null==o?void 0:o.tokenType)||"Bearer",scope:null==o?void 0:o.scope});if(s({tokens:i,token:t,isAuthenticated:!!t}),r.enabled)try{r.storage.setItem(r.tokenKey,t)}catch(r){null===(n=e.onError)||void 0===n||n.call(e,r)}}}});return Object.assign(s,{config:e})};function f(){var e={};return function(r,t){var n=String(r);if(!e[n]){var o=u(t);e[n]=l(o)}return e[n]}}var k=s(155),d=s(742),h=s.n(d),p=function(e,r,t,n){return new(t||(t=Promise))(function(o,s){function a(e){try{u(n.next(e))}catch(e){s(e)}}function i(e){try{u(n.throw(e))}catch(e){s(e)}}function u(e){var r;e.done?o(e.value):(r=e.value,r instanceof t?r:new t(function(e){e(r)})).then(a,i)}u((n=n.apply(e,r||[])).next())})},v=function(e,r){var t,n,o,s,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return s={next:i(0),throw:i(1),return:i(2)},"function"==typeof Symbol&&(s[Symbol.iterator]=function(){return this}),s;function i(i){return function(u){return function(i){if(t)throw new TypeError("Generator is already executing.");for(;s&&(s=0,i[0]&&(a=0)),a;)try{if(t=1,n&&(o=2&i[0]?n.return:i[0]?n.throw||((o=n.return)&&o.call(n),0):n.next)&&!(o=o.call(n,i[1])).done)return o;switch(n=0,o&&(i=[2&i[0],o.value]),i[0]){case 0:case 1:o=i;break;case 4:return a.label++,{value:i[1],done:!1};case 5:a.label++,n=i[1],i=[0];continue;case 7:i=a.ops.pop(),a.trys.pop();continue;default:if(!((o=(o=a.trys).length>0&&o[o.length-1])||6!==i[0]&&2!==i[0])){a=0;continue}if(3===i[0]&&(!o||i[1]>o[0]&&i[1]<o[3])){a.label=i[1];break}if(6===i[0]&&a.label<o[1]){a.label=o[1],o=i;break}if(o&&a.label<o[2]){a.label=o[2],a.ops.push(i);break}o[2]&&a.ops.pop(),a.trys.pop();continue}i=r.call(e,a)}catch(e){i=[6,e],n=0}finally{t=o=0}if(5&i[0])throw i[1];return{value:i[0]?i[1]:void 0,done:!0}}([i,u])}}};function y(e){var r=this,t=e(),n=t.setTokens,o=t.setUser,s=t.unsetUser,a=t.tokens,i=t.user,u=t.isTokenExpired,c=e.config,l=e(),f=(l.setToken,l.token,(0,k.useCallback)(function(){return p(r,void 0,void 0,function(){var e,r,t,o,i;return v(this,function(u){switch(u.label){case 0:if(!(null==a?void 0:a.refreshToken))return[2,!1];u.label=1;case 1:return u.trys.push([1,3,,4]),[4,c.axios.post(c.tokenUrl,{grant_type:"refresh_token",refresh_token:a.refreshToken})];case 2:return e=u.sent(),r=c.extractTokens(e.data),n(r),d(r.accessToken,r.tokenType),null===(o=c.onTokenRefresh)||void 0===o||o.call(c,r),[2,!0];case 3:return t=u.sent(),s(),d(),null===(i=c.onError)||void 0===i||i.call(c,t),[2,!1];case 4:return[2]}})})},[null==a?void 0:a.refreshToken,c,n,s]));(0,k.useEffect)(function(){var e,r;if(null==a?void 0:a.accessToken){if(d(a.accessToken,a.tokenType),u())return void(a.refreshToken&&c.autoRefresh?f():s());if(a.expiresAt&&a.refreshToken&&c.autoRefresh){var t=a.expiresAt-Date.now(),n=Math.max(t-c.refreshThreshold,0),o=setTimeout(function(){f()},n);return function(){return clearTimeout(o)}}try{i||!c.userInfoUrl&&!c.getUserUrl||y()}catch(t){h().isAxiosError(t)&&403===(null===(e=t.response)||void 0===e?void 0:e.status)&&(s(),d()),null===(r=c.onError)||void 0===r||r.call(c,t)}}},[a,i,c.autoRefresh,c.refreshThreshold,c.userInfoUrl,c.getUserUrl,u,f,s]);var d=function(e,r){void 0!==e&&e?c.axios.defaults.headers.common.Authorization=c.formatAuthHeader(e,r):delete c.axios.defaults.headers.common.Authorization},y=function(){return p(r,void 0,void 0,function(){var e,r,t,n;return v(this,function(a){switch(a.label){case 0:if(!(e=c.userInfoUrl||c.getUserUrl))return[2];a.label=1;case 1:return a.trys.push([1,3,,4]),[4,c.axios.get(e)];case 2:return r=a.sent(),o(r.data),[3,4];case 3:return t=a.sent(),s(),d(),null===(n=c.onError)||void 0===n||n.call(c,t),[3,4];case 4:return[2]}})})};return{login:function(e,t){return p(r,void 0,void 0,function(){var r,o,a,u,l;return v(this,function(f){switch(f.label){case 0:return f.trys.push([0,4,,5]),[4,c.axios.post(c.tokenUrl,e)];case 1:return r=f.sent(),o=c.extractTokens(r.data),n(o),d(o.accessToken,o.tokenType),c.userInfoUrl||c.getUserUrl?[4,y()]:[3,3];case 2:f.sent(),f.label=3;case 3:return i&&(null===(u=c.onLogin)||void 0===u||u.call(c,i)),null==t||t(),[3,5];case 4:return a=f.sent(),s(),d(),null===(l=c.onError)||void 0===l||l.call(c,a),[3,5];case 5:return[2]}})})},getCurrentUser:y,logout:function(){return p(r,void 0,void 0,function(){var e,r,t,n;return v(this,function(o){switch(o.label){case 0:return o.trys.push([0,5,6,7]),(e=c.revokeUrl||c.logoutUrl)?c.revokeUrl&&(null==a?void 0:a.refreshToken)?[4,c.axios.post(e,{token:a.refreshToken,token_type_hint:"refresh_token"})]:[3,2]:[3,4];case 1:return o.sent(),[3,4];case 2:return[4,c.axios.post(e)];case 3:o.sent(),o.label=4;case 4:return[3,7];case 5:return r=o.sent(),null===(t=c.onError)||void 0===t||t.call(c,r),[3,7];case 6:return s(),d(),null===(n=c.onLogout)||void 0===n||n.call(c),[7];case 7:return[2]}})})},refreshTokens:f}}return a})());
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","mappings":"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","sources":["webpack://@jasperoosthoek/zustand-auth-registry/webpack/universalModuleDefinition","webpack://@jasperoosthoek/zustand-auth-registry/external umd \"react\"","webpack://@jasperoosthoek/zustand-auth-registry/external umd \"zustand\"","webpack://@jasperoosthoek/zustand-auth-registry/external umd \"axios\"","webpack://@jasperoosthoek/zustand-auth-registry/webpack/bootstrap","webpack://@jasperoosthoek/zustand-auth-registry/webpack/runtime/compat get default export","webpack://@jasperoosthoek/zustand-auth-registry/webpack/runtime/define property getters","webpack://@jasperoosthoek/zustand-auth-registry/webpack/runtime/hasOwnProperty shorthand","webpack://@jasperoosthoek/zustand-auth-registry/webpack/runtime/make namespace object","webpack://@jasperoosthoek/zustand-auth-registry/./src/authConfig.ts","webpack://@jasperoosthoek/zustand-auth-registry/./src/authStore.ts","webpack://@jasperoosthoek/zustand-auth-registry/./src/createAuthRegistry.ts","webpack://@jasperoosthoek/zustand-auth-registry/./src/useAuth.ts"],"sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"zustand\"), require(\"react\"), require(\"axios\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"zustand\", \"react\", \"axios\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"@jasperoosthoek/zustand-auth-registry\"] = factory(require(\"zustand\"), require(\"react\"), require(\"axios\"));\n\telse\n\t\troot[\"@jasperoosthoek/zustand-auth-registry\"] = factory(root[\"zustand\"], root[\"react\"], root[\"axios\"]);\n})(this, (__WEBPACK_EXTERNAL_MODULE__287__, __WEBPACK_EXTERNAL_MODULE__155__, __WEBPACK_EXTERNAL_MODULE__742__) => {\nreturn ","module.exports = __WEBPACK_EXTERNAL_MODULE__155__;","module.exports = __WEBPACK_EXTERNAL_MODULE__287__;","module.exports = __WEBPACK_EXTERNAL_MODULE__742__;","// The module cache\nvar __webpack_module_cache__ = {};\n\n// The require function\nfunction __webpack_require__(moduleId) {\n\t// Check if module is in cache\n\tvar cachedModule = __webpack_module_cache__[moduleId];\n\tif (cachedModule !== undefined) {\n\t\treturn cachedModule.exports;\n\t}\n\t// Create a new module (and put it into the cache)\n\tvar module = __webpack_module_cache__[moduleId] = {\n\t\t// no module.id needed\n\t\t// no module.loaded needed\n\t\texports: {}\n\t};\n\n\t// Execute the module function\n\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n\n\t// Return the exports of the module\n\treturn module.exports;\n}\n\n","// getDefaultExport function for compatibility with non-harmony modules\n__webpack_require__.n = (module) => {\n\tvar getter = module && module.__esModule ?\n\t\t() => (module['default']) :\n\t\t() => (module);\n\t__webpack_require__.d(getter, { a: getter });\n\treturn getter;\n};","// define getter functions for harmony exports\n__webpack_require__.d = (exports, definition) => {\n\tfor(var key in definition) {\n\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n\t\t}\n\t}\n};","__webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))","// define __esModule on exports\n__webpack_require__.r = (exports) => {\n\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n\t}\n\tObject.defineProperty(exports, '__esModule', { value: true });\n};","import { AxiosInstance } from 'axios';\n\n// OAuth 2.0 token data structure\nexport type TokenData = {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n tokenType: string;\n scope?: string[];\n};\n\n// Backward compatibility: extract single token vs OAuth token data\nexport type TokenExtractor = (data: any) => string | TokenData;\n\nexport type AuthConfig<U> = {\n axios: AxiosInstance;\n \n // OAuth 2.0 compliant endpoints (new defaults)\n tokenUrl?: string;\n revokeUrl?: string;\n userInfoUrl?: string;\n \n // Backward compatibility: Django-style endpoints\n loginUrl?: string;\n logoutUrl?: string;\n getUserUrl?: string;\n \n // OAuth 2.0 compliant token extraction\n extractTokens?: (data: any) => TokenData;\n extractAccessToken?: (data: any) => string;\n extractRefreshToken?: (data: any) => string | undefined;\n extractExpiresIn?: (data: any) => number | undefined;\n extractTokenType?: (data: any) => string;\n extractScope?: (data: any) => string[] | undefined;\n \n // Backward compatibility: single token extraction\n extractToken?: (data: any) => string;\n \n formatAuthHeader?: (token: string, tokenType?: string) => string;\n \n // OAuth 2.0 features\n autoRefresh?: boolean;\n refreshThreshold?: number; // ms before expiry to refresh\n \n persistence?: {\n enabled?: boolean;\n storage?: Storage;\n tokenKey?: string;\n refreshTokenKey?: string;\n userKey?: string;\n expiryKey?: string;\n };\n \n onError?: (error: any) => void;\n onLogin?: (user: U) => void;\n onLogout?: () => void;\n onTokenRefresh?: (tokens: TokenData) => void;\n};\n\nexport type ValidatedAuthConfig<U> = {\n axios: AxiosInstance;\n \n // Resolved endpoints (OAuth preferred, Django fallback)\n tokenUrl: string;\n revokeUrl?: string;\n userInfoUrl?: string;\n \n // Backward compatibility endpoints\n loginUrl?: string;\n logoutUrl?: string;\n getUserUrl?: string;\n \n // Token extraction functions\n extractTokens: (data: any) => TokenData;\n extractToken?: (data: any) => string;\n \n formatAuthHeader: (token: string, tokenType?: string) => string;\n \n // OAuth features\n autoRefresh: boolean;\n refreshThreshold: number;\n \n persistence: {\n enabled: boolean;\n storage: Storage;\n tokenKey: string;\n refreshTokenKey: string;\n userKey: string;\n expiryKey: string;\n };\n \n onError?: (error: any) => void;\n onLogin?: (user: U) => void;\n onLogout?: () => void;\n onTokenRefresh?: (tokens: TokenData) => void;\n};\n\nexport const validateAuthConfig = <U>(config: AuthConfig<U>): ValidatedAuthConfig<U> => {\n if (!config.axios) {\n throw new Error('AuthConfig: axios instance is required');\n }\n\n // Determine token endpoint (OAuth preferred, Django fallback)\n const tokenUrl = config.tokenUrl || config.loginUrl;\n if (!tokenUrl) {\n throw new Error('AuthConfig: tokenUrl or loginUrl is required');\n }\n\n // Keep revokeUrl and logoutUrl distinct for proper OAuth/legacy behavior\n const revokeUrl = config.revokeUrl;\n\n // Determine user info endpoint\n const userInfoUrl = config.userInfoUrl || config.getUserUrl;\n\n // Create OAuth-compliant token extraction function\n const extractTokens = createTokenExtractor(config);\n\n const defaultPersistence = {\n enabled: true,\n storage: typeof window !== 'undefined' && window.localStorage ? window.localStorage : ({} as Storage),\n tokenKey: 'token',\n refreshTokenKey: 'refresh_token',\n userKey: 'user',\n expiryKey: 'expires_at',\n };\n\n return {\n axios: config.axios,\n tokenUrl,\n revokeUrl,\n userInfoUrl,\n // Backward compatibility\n loginUrl: config.loginUrl,\n logoutUrl: config.logoutUrl,\n getUserUrl: config.getUserUrl,\n extractTokens,\n extractToken: config.extractToken,\n formatAuthHeader: config.formatAuthHeader || ((token: string, tokenType: string = 'Bearer') => `${tokenType} ${token}`),\n autoRefresh: config.autoRefresh ?? true,\n refreshThreshold: config.refreshThreshold ?? 300000, // 5 minutes\n persistence: {\n ...defaultPersistence,\n ...config.persistence,\n },\n onError: config.onError,\n onLogin: config.onLogin,\n onLogout: config.onLogout,\n onTokenRefresh: config.onTokenRefresh,\n };\n};\n\n// Helper function to create OAuth-compliant token extractor with backward compatibility\nfunction createTokenExtractor<U>(config: AuthConfig<U>): (data: any) => TokenData {\n return (data: any): TokenData => {\n // If custom extractTokens function provided, use it\n if (config.extractTokens) {\n return config.extractTokens(data);\n }\n\n // OAuth 2.0 compliant extraction (preferred)\n if (data.access_token) {\n return {\n accessToken: config.extractAccessToken ? config.extractAccessToken(data) : data.access_token,\n refreshToken: config.extractRefreshToken ? config.extractRefreshToken(data) : data.refresh_token,\n expiresAt: config.extractExpiresIn \n ? (config.extractExpiresIn(data) ? Date.now() + (config.extractExpiresIn(data)! * 1000) : undefined)\n : (data.expires_in ? Date.now() + (data.expires_in * 1000) : undefined),\n tokenType: config.extractTokenType ? config.extractTokenType(data) : (data.token_type || 'Bearer'),\n scope: config.extractScope ? config.extractScope(data) : (data.scope ? data.scope.split(' ') : undefined),\n };\n }\n\n // Single token fallback (backward compatibility)\n if (config.extractToken || data.auth_token || data.token) {\n const token = config.extractToken ? config.extractToken(data) : (data.auth_token || data.token);\n return {\n accessToken: token,\n tokenType: 'Bearer', // Standard default\n };\n }\n\n throw new Error('No valid token found in response. Provide extractTokens, extractToken, or ensure response contains access_token/auth_token field.');\n };\n}","import { create, StoreApi, UseBoundStore } from 'zustand';\nimport { ValidatedAuthConfig, TokenData } from './authConfig';\n\nexport type AuthState<U> = {\n isAuthenticated: boolean;\n user: U | null;\n tokens: TokenData | null;\n \n // OAuth 2.0 methods\n setTokens: (tokens: TokenData) => void;\n setUser: (user: U) => void;\n unsetUser: () => void;\n isTokenExpired: () => boolean;\n \n // Backward compatibility\n token: string;\n setToken: (token: string) => void;\n};\n\nexport type AuthStore<U> = UseBoundStore<StoreApi<AuthState<U>>> & {\n config: ValidatedAuthConfig<U>;\n};\n\nexport const createAuthStore = <U>(config: ValidatedAuthConfig<U>): AuthStore<U> => {\n const { persistence } = config;\n \n const getStoredTokens = (): TokenData | null => {\n if (!persistence.enabled) return null;\n try {\n const accessToken = persistence.storage.getItem(persistence.tokenKey);\n if (!accessToken) return null;\n \n const refreshToken = persistence.storage.getItem(persistence.refreshTokenKey);\n const expiryString = persistence.storage.getItem(persistence.expiryKey);\n const expiresAt = expiryString ? parseInt(expiryString, 10) : undefined;\n \n return {\n accessToken,\n refreshToken: refreshToken || undefined,\n expiresAt: expiresAt && !isNaN(expiresAt) ? expiresAt : undefined,\n tokenType: 'Bearer', // Default, will be updated on setTokens\n };\n } catch {\n return null;\n }\n };\n\n const getStoredUser = (): U | null => {\n if (!persistence.enabled) return null;\n try {\n const userString = persistence.storage.getItem(persistence.userKey);\n return userString ? (JSON.parse(userString) as U) : null;\n } catch {\n return null;\n }\n };\n\n const initialTokens = getStoredTokens();\n const initialUser = getStoredUser();\n const initialIsAuthenticated = !!initialTokens?.accessToken;\n\n const store = create<AuthState<U>>((set, get) => ({\n tokens: initialTokens,\n user: initialUser,\n isAuthenticated: initialIsAuthenticated,\n\n // OAuth 2.0 methods\n setTokens: (tokens: TokenData) => {\n const user = get().user;\n const isAuthenticated = !!tokens.accessToken;\n \n set({ tokens, isAuthenticated, token: tokens.accessToken });\n \n if (persistence.enabled) {\n try {\n persistence.storage.setItem(persistence.tokenKey, tokens.accessToken);\n \n if (tokens.refreshToken) {\n persistence.storage.setItem(persistence.refreshTokenKey, tokens.refreshToken);\n } else {\n persistence.storage.removeItem(persistence.refreshTokenKey);\n }\n \n if (tokens.expiresAt) {\n persistence.storage.setItem(persistence.expiryKey, tokens.expiresAt.toString());\n } else {\n persistence.storage.removeItem(persistence.expiryKey);\n }\n } catch (error) {\n config.onError?.(error);\n }\n }\n },\n\n setUser: (user: U) => {\n const tokens = get().tokens;\n const isAuthenticated = !!tokens?.accessToken;\n \n set({ user, isAuthenticated });\n \n if (persistence.enabled) {\n try {\n persistence.storage.setItem(persistence.userKey, JSON.stringify(user));\n } catch (error) {\n config.onError?.(error);\n }\n }\n },\n\n unsetUser: () => {\n set({ user: null, tokens: null, isAuthenticated: false, token: '' });\n \n if (persistence.enabled) {\n try {\n persistence.storage.removeItem(persistence.tokenKey);\n persistence.storage.removeItem(persistence.refreshTokenKey);\n persistence.storage.removeItem(persistence.userKey);\n persistence.storage.removeItem(persistence.expiryKey);\n } catch (error) {\n config.onError?.(error);\n }\n }\n },\n\n isTokenExpired: () => {\n const tokens = get().tokens;\n if (!tokens?.expiresAt) return false; // No expiry info means no expiration\n return Date.now() >= tokens.expiresAt;\n },\n\n // Backward compatibility - computed property\n token: initialTokens?.accessToken || '',\n\n setToken: (token: string) => {\n const currentTokens = get().tokens;\n const user = get().user;\n const newTokens: TokenData = {\n accessToken: token,\n refreshToken: currentTokens?.refreshToken,\n expiresAt: currentTokens?.expiresAt,\n tokenType: currentTokens?.tokenType || 'Bearer', // Standard default\n scope: currentTokens?.scope,\n };\n \n const isAuthenticated = !!token;\n set({ tokens: newTokens, token, isAuthenticated });\n \n // Handle persistence\n if (persistence.enabled) {\n try {\n persistence.storage.setItem(persistence.tokenKey, token);\n } catch (error) {\n config.onError?.(error);\n }\n }\n },\n }));\n\n return Object.assign(store, { config });\n};\n","import { AuthConfig, validateAuthConfig } from './authConfig';\nimport { createAuthStore, AuthStore } from './authStore';\n\nexport function createAuthRegistry<AuthModels extends Record<string, any>>() {\n const registry: Record<string, AuthStore<any>> = {};\n\n function getAuthStore<K extends keyof AuthModels>(\n key: K,\n config: AuthConfig<AuthModels[K]>\n ): AuthStore<AuthModels[K]> {\n const stringKey = String(key);\n \n if (!registry[stringKey]) {\n const validatedConfig = validateAuthConfig(config);\n registry[stringKey] = createAuthStore(validatedConfig);\n }\n \n return registry[stringKey];\n }\n\n return getAuthStore;\n}","import { useEffect, useCallback } from 'react';\nimport axios from 'axios';\nimport { AuthStore } from './authStore';\nimport { TokenData } from './authConfig';\n\nexport function useAuth<U>(store: AuthStore<U>) {\n const { setTokens, setUser, unsetUser, tokens, user, isTokenExpired } = store();\n const config = store.config;\n\n // Backward compatibility\n const { setToken, token } = store();\n\n // OAuth 2.0 refresh token functionality\n const refreshTokens = useCallback(async (): Promise<boolean> => {\n if (!tokens?.refreshToken) {\n return false;\n }\n\n try {\n const response = await config.axios.post(config.tokenUrl, {\n grant_type: 'refresh_token',\n refresh_token: tokens.refreshToken,\n });\n\n const newTokens = config.extractTokens(response.data);\n setTokens(newTokens);\n setAxiosAuth(newTokens.accessToken, newTokens.tokenType);\n \n config.onTokenRefresh?.(newTokens);\n return true;\n } catch (error) {\n // Refresh failed, clear tokens\n unsetUser();\n setAxiosAuth();\n config.onError?.(error);\n return false;\n }\n }, [tokens?.refreshToken, config, setTokens, unsetUser]);\n\n // Auto-refresh and authentication setup\n useEffect(() => {\n // Handle current tokens\n if (tokens?.accessToken) {\n // Set axios headers immediately\n setAxiosAuth(tokens.accessToken, tokens.tokenType);\n\n // Check if token is expired or about to expire\n if (isTokenExpired()) {\n // Token is already expired, try to refresh\n if (tokens.refreshToken && config.autoRefresh) {\n refreshTokens();\n } else {\n unsetUser();\n }\n return;\n }\n\n // Set up auto-refresh timer if we have expiry info\n if (tokens.expiresAt && tokens.refreshToken && config.autoRefresh) {\n const timeUntilExpiry = tokens.expiresAt - Date.now();\n const refreshTime = Math.max(timeUntilExpiry - config.refreshThreshold, 0);\n\n const timer = setTimeout(() => {\n refreshTokens();\n }, refreshTime);\n\n return () => clearTimeout(timer);\n }\n\n // Try to get user info if missing\n try {\n if (!user && (config.userInfoUrl || config.getUserUrl)) {\n getCurrentUser();\n }\n } catch (error) {\n if (axios.isAxiosError(error) && error.response?.status === 403) {\n unsetUser();\n setAxiosAuth();\n }\n config.onError?.(error);\n }\n }\n }, [tokens, user, config.autoRefresh, config.refreshThreshold, config.userInfoUrl, config.getUserUrl, isTokenExpired, refreshTokens, unsetUser]);\n\n const setAxiosAuth = (token?: string, tokenType?: string) => {\n if (typeof token !== 'undefined' && token) {\n config.axios.defaults.headers.common['Authorization'] = config.formatAuthHeader(token, tokenType);\n } else {\n delete config.axios.defaults.headers.common['Authorization'];\n }\n };\n\n const login = async (\n credentials: Record<string, string>,\n callback?: () => void\n ) => {\n try {\n const res = await config.axios.post(config.tokenUrl, credentials);\n const tokens = config.extractTokens(res.data);\n setTokens(tokens);\n setAxiosAuth(tokens.accessToken, tokens.tokenType);\n \n if (config.userInfoUrl || config.getUserUrl) {\n await getCurrentUser();\n }\n \n if (user) {\n config.onLogin?.(user);\n }\n callback?.();\n } catch (err) {\n unsetUser();\n setAxiosAuth();\n config.onError?.(err);\n }\n };\n\n const getCurrentUser = async () => {\n const userUrl = config.userInfoUrl || config.getUserUrl;\n if (!userUrl) return;\n try {\n const res = await config.axios.get<U>(userUrl);\n setUser(res.data);\n } catch (err) {\n unsetUser();\n setAxiosAuth();\n config.onError?.(err);\n }\n };\n\n const logout = async () => {\n try {\n // If we have a revoke/logout URL, call it\n const logoutUrl = config.revokeUrl || config.logoutUrl;\n if (logoutUrl) {\n if (config.revokeUrl && tokens?.refreshToken) {\n // OAuth revoke\n await config.axios.post(logoutUrl, {\n token: tokens.refreshToken,\n token_type_hint: 'refresh_token'\n });\n } else {\n // Simple logout\n await config.axios.post(logoutUrl);\n }\n }\n } catch (err) {\n config.onError?.(err);\n } finally {\n unsetUser();\n setAxiosAuth();\n config.onLogout?.();\n }\n };\n\n return { login, getCurrentUser, logout, refreshTokens };\n}"],"names":["root","factory","exports","module","require","define","amd","this","__WEBPACK_EXTERNAL_MODULE__287__","__WEBPACK_EXTERNAL_MODULE__155__","__WEBPACK_EXTERNAL_MODULE__742__","__webpack_module_cache__","__webpack_require__","moduleId","cachedModule","undefined","__webpack_modules__","n","getter","__esModule","d","a","definition","key","o","Object","defineProperty","enumerable","get","obj","prop","prototype","hasOwnProperty","call","r","Symbol","toStringTag","value","validateAuthConfig","config","axios","Error","tokenUrl","loginUrl","revokeUrl","userInfoUrl","getUserUrl","extractTokens","data","access_token","accessToken","extractAccessToken","refreshToken","extractRefreshToken","refresh_token","expiresAt","extractExpiresIn","Date","now","expires_in","tokenType","extractTokenType","token_type","scope","extractScope","split","extractToken","auth_token","token","createTokenExtractor","defaultPersistence","enabled","storage","window","localStorage","tokenKey","refreshTokenKey","userKey","expiryKey","logoutUrl","formatAuthHeader","autoRefresh","refreshThreshold","persistence","onError","onLogin","onLogout","onTokenRefresh","createAuthStore","initialTokens","getItem","expiryString","parseInt","isNaN","getStoredTokens","initialUser","userString","JSON","parse","getStoredUser","initialIsAuthenticated","store","create","set","tokens","user","isAuthenticated","setTokens","setItem","removeItem","toString","error","setUser","stringify","unsetUser","isTokenExpired","setToken","currentTokens","newTokens","assign","createAuthRegistry","registry","stringKey","String","validatedConfig","useAuth","refreshTokens","useCallback","post","grant_type","response","setAxiosAuth","useEffect","timeUntilExpiry","refreshTime","Math","max","setTimeout","clearTimeout","getCurrentUser","status","defaults","headers","common","userUrl","res","login","credentials","callback","logout","token_type_hint"],"sourceRoot":""}
@@ -0,0 +1 @@
1
+ import '@testing-library/react';
@@ -0,0 +1,7 @@
1
+ import { AuthStore } from './authStore';
2
+ export declare function useAuth<U>(store: AuthStore<U>): {
3
+ login: (credentials: Record<string, string>, callback?: () => void) => Promise<void>;
4
+ getCurrentUser: () => Promise<void>;
5
+ logout: () => Promise<void>;
6
+ refreshTokens: () => Promise<boolean>;
7
+ };