@swr-login/react 0.1.0
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 +21 -0
- package/README.md +91 -0
- package/dist/index.cjs +344 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +250 -0
- package/dist/index.d.ts +250 -0
- package/dist/index.js +330 -0
- package/dist/index.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 swr-login contributors
|
|
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,91 @@
|
|
|
1
|
+
# @swr-login/react
|
|
2
|
+
|
|
3
|
+
> React bindings for swr-login: Provider, Hooks, and AuthGuard component.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@swr-login/react)
|
|
6
|
+
[](https://github.com/swr-login/swr-login/blob/main/LICENSE)
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @swr-login/react @swr-login/adapter-jwt @swr-login/plugin-password
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Start
|
|
15
|
+
|
|
16
|
+
```tsx
|
|
17
|
+
import { SWRLoginProvider, useLogin, useUser, useLogout } from '@swr-login/react';
|
|
18
|
+
import { JWTAdapter } from '@swr-login/adapter-jwt';
|
|
19
|
+
import { PasswordPlugin } from '@swr-login/plugin-password';
|
|
20
|
+
|
|
21
|
+
function App() {
|
|
22
|
+
return (
|
|
23
|
+
<SWRLoginProvider
|
|
24
|
+
config={{
|
|
25
|
+
adapter: JWTAdapter(),
|
|
26
|
+
plugins: [PasswordPlugin({ loginUrl: '/api/login' })],
|
|
27
|
+
fetchUser: (token) =>
|
|
28
|
+
fetch('/api/me', { headers: { Authorization: `Bearer ${token}` } })
|
|
29
|
+
.then(r => r.json()),
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<MyApp />
|
|
33
|
+
</SWRLoginProvider>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function LoginButton() {
|
|
38
|
+
const { login, isLoading } = useLogin('password');
|
|
39
|
+
const { user, isAuthenticated } = useUser();
|
|
40
|
+
const { logout } = useLogout();
|
|
41
|
+
|
|
42
|
+
if (isAuthenticated) {
|
|
43
|
+
return (
|
|
44
|
+
<div>
|
|
45
|
+
<span>Hello, {user.name}!</span>
|
|
46
|
+
<button onClick={() => logout()}>Sign Out</button>
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return (
|
|
52
|
+
<button
|
|
53
|
+
onClick={() => login({ username: 'alice', password: 'secret' })}
|
|
54
|
+
disabled={isLoading}
|
|
55
|
+
>
|
|
56
|
+
Sign In
|
|
57
|
+
</button>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Hooks
|
|
63
|
+
|
|
64
|
+
| Hook | Purpose |
|
|
65
|
+
|------|---------|
|
|
66
|
+
| `useLogin(pluginName?)` | Trigger login flow via any registered plugin |
|
|
67
|
+
| `useUser<T>()` | Get current user with SWR caching & auto-revalidation |
|
|
68
|
+
| `useLogout()` | Secure logout with cross-tab broadcast |
|
|
69
|
+
| `useSession()` | Access raw tokens, expiry info |
|
|
70
|
+
| `usePermission()` | Check roles & permissions declaratively |
|
|
71
|
+
|
|
72
|
+
## AuthGuard
|
|
73
|
+
|
|
74
|
+
```tsx
|
|
75
|
+
<AuthGuard
|
|
76
|
+
permissions={['admin', 'editor']}
|
|
77
|
+
requireAll={false}
|
|
78
|
+
fallback={<Navigate to="/login" />}
|
|
79
|
+
loadingComponent={<Skeleton />}
|
|
80
|
+
>
|
|
81
|
+
<ProtectedContent />
|
|
82
|
+
</AuthGuard>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Part of swr-login
|
|
86
|
+
|
|
87
|
+
This package is the React layer of [swr-login](https://github.com/swr-login/swr-login). The framework-agnostic core is [`@swr-login/core`](https://www.npmjs.com/package/@swr-login/core).
|
|
88
|
+
|
|
89
|
+
## License
|
|
90
|
+
|
|
91
|
+
[MIT](https://github.com/swr-login/swr-login/blob/main/LICENSE)
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@swr-login/core');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
6
|
+
var useSWR = require('swr');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var useSWR__default = /*#__PURE__*/_interopDefault(useSWR);
|
|
11
|
+
|
|
12
|
+
// src/provider.tsx
|
|
13
|
+
var AuthContext = react.createContext(null);
|
|
14
|
+
function useAuthContext() {
|
|
15
|
+
const ctx = react.useContext(AuthContext);
|
|
16
|
+
if (!ctx) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
"[swr-login] useAuthContext must be used within <SWRLoginProvider>. Wrap your app with <SWRLoginProvider> to use swr-login hooks."
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
return ctx;
|
|
22
|
+
}
|
|
23
|
+
function SWRLoginProvider({ config, children }) {
|
|
24
|
+
const initializedRef = react.useRef(false);
|
|
25
|
+
const contextValue = react.useMemo(() => {
|
|
26
|
+
const emitter = new core.AuthEventEmitter();
|
|
27
|
+
const stateMachine = new core.AuthStateMachine(emitter);
|
|
28
|
+
const tokenManager = new core.TokenManager(config.adapter, emitter, stateMachine);
|
|
29
|
+
const pluginManager = new core.PluginManager(tokenManager, emitter);
|
|
30
|
+
pluginManager.register(...config.plugins);
|
|
31
|
+
const enableSync = config.security?.enableBroadcastSync !== false;
|
|
32
|
+
const broadcastSync = enableSync && typeof window !== "undefined" ? new core.BroadcastSync() : null;
|
|
33
|
+
if (config.onLogin) {
|
|
34
|
+
emitter.on("login", ({ user }) => config.onLogin?.(user));
|
|
35
|
+
}
|
|
36
|
+
if (config.onLogout) {
|
|
37
|
+
emitter.on("logout", () => config.onLogout?.());
|
|
38
|
+
}
|
|
39
|
+
if (config.onError) {
|
|
40
|
+
emitter.on("error", ({ error }) => config.onError?.(error));
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
pluginManager,
|
|
44
|
+
tokenManager,
|
|
45
|
+
emitter,
|
|
46
|
+
stateMachine,
|
|
47
|
+
broadcastSync,
|
|
48
|
+
config
|
|
49
|
+
};
|
|
50
|
+
}, [config]);
|
|
51
|
+
react.useEffect(() => {
|
|
52
|
+
if (initializedRef.current) return;
|
|
53
|
+
initializedRef.current = true;
|
|
54
|
+
const {
|
|
55
|
+
pluginManager,
|
|
56
|
+
broadcastSync,
|
|
57
|
+
tokenManager,
|
|
58
|
+
stateMachine,
|
|
59
|
+
emitter,
|
|
60
|
+
config: cfg
|
|
61
|
+
} = contextValue;
|
|
62
|
+
pluginManager.initializeAll().catch((err) => {
|
|
63
|
+
console.error("[swr-login] Plugin initialization error:", err);
|
|
64
|
+
});
|
|
65
|
+
const existingToken = tokenManager.getAccessToken();
|
|
66
|
+
if (existingToken && !tokenManager.isExpired()) {
|
|
67
|
+
stateMachine.transition("authenticated");
|
|
68
|
+
} else if (existingToken && tokenManager.isExpired()) {
|
|
69
|
+
stateMachine.transition("unauthenticated");
|
|
70
|
+
emitter.emit("token-expired", void 0);
|
|
71
|
+
}
|
|
72
|
+
if (broadcastSync) {
|
|
73
|
+
const unsubscribe = broadcastSync.onMessage((message) => {
|
|
74
|
+
switch (message.type) {
|
|
75
|
+
case "LOGOUT":
|
|
76
|
+
tokenManager.clearTokens();
|
|
77
|
+
stateMachine.transition("unauthenticated");
|
|
78
|
+
emitter.emit("logout", void 0);
|
|
79
|
+
break;
|
|
80
|
+
case "LOGIN":
|
|
81
|
+
case "TOKEN_REFRESH":
|
|
82
|
+
if (cfg.cacheAdapter) {
|
|
83
|
+
cfg.cacheAdapter.revalidate();
|
|
84
|
+
}
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return () => {
|
|
89
|
+
unsubscribe();
|
|
90
|
+
broadcastSync.destroy();
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
}, [contextValue]);
|
|
94
|
+
react.useEffect(() => {
|
|
95
|
+
const { config: cfg, tokenManager, stateMachine, emitter } = contextValue;
|
|
96
|
+
if (!cfg.security?.clearOnHidden || typeof document === "undefined") return;
|
|
97
|
+
let timeoutId = null;
|
|
98
|
+
const handleVisibilityChange = () => {
|
|
99
|
+
if (document.hidden) {
|
|
100
|
+
const delay = cfg.security?.clearOnHiddenDelay ?? 3e5;
|
|
101
|
+
timeoutId = setTimeout(() => {
|
|
102
|
+
tokenManager.clearTokens();
|
|
103
|
+
stateMachine.transition("unauthenticated");
|
|
104
|
+
emitter.emit("logout", void 0);
|
|
105
|
+
}, delay);
|
|
106
|
+
} else {
|
|
107
|
+
if (timeoutId) {
|
|
108
|
+
clearTimeout(timeoutId);
|
|
109
|
+
timeoutId = null;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
114
|
+
return () => {
|
|
115
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
116
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
117
|
+
};
|
|
118
|
+
}, [contextValue]);
|
|
119
|
+
return /* @__PURE__ */ jsxRuntime.jsx(AuthContext.Provider, { value: contextValue, children });
|
|
120
|
+
}
|
|
121
|
+
function useLogin(pluginName) {
|
|
122
|
+
const { pluginManager, stateMachine, config } = useAuthContext();
|
|
123
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
124
|
+
const [error, setError] = react.useState(null);
|
|
125
|
+
const login = react.useCallback(
|
|
126
|
+
async (credentialsOrPluginName, maybeCredentials) => {
|
|
127
|
+
let resolvedPlugin;
|
|
128
|
+
let resolvedCredentials;
|
|
129
|
+
if (typeof credentialsOrPluginName === "string" && !pluginName) {
|
|
130
|
+
resolvedPlugin = credentialsOrPluginName;
|
|
131
|
+
resolvedCredentials = maybeCredentials ?? {};
|
|
132
|
+
} else if (pluginName) {
|
|
133
|
+
resolvedPlugin = pluginName;
|
|
134
|
+
resolvedCredentials = credentialsOrPluginName;
|
|
135
|
+
} else {
|
|
136
|
+
throw new Error(
|
|
137
|
+
"[swr-login] Plugin name is required. Provide it to useLogin() or login()."
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
setIsLoading(true);
|
|
141
|
+
setError(null);
|
|
142
|
+
stateMachine.transition("authenticating");
|
|
143
|
+
try {
|
|
144
|
+
const response = await pluginManager.login(resolvedPlugin, resolvedCredentials);
|
|
145
|
+
stateMachine.transition("authenticated");
|
|
146
|
+
if (config.cacheAdapter) {
|
|
147
|
+
await config.cacheAdapter.setUser(response.user);
|
|
148
|
+
}
|
|
149
|
+
return response;
|
|
150
|
+
} catch (err) {
|
|
151
|
+
const authError = err instanceof Error ? err : new Error("Login failed");
|
|
152
|
+
setError(authError);
|
|
153
|
+
stateMachine.transition("error");
|
|
154
|
+
throw authError;
|
|
155
|
+
} finally {
|
|
156
|
+
setIsLoading(false);
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
[pluginManager, stateMachine, config, pluginName]
|
|
160
|
+
);
|
|
161
|
+
const reset = react.useCallback(() => {
|
|
162
|
+
setError(null);
|
|
163
|
+
}, []);
|
|
164
|
+
return { login, isLoading, error, reset };
|
|
165
|
+
}
|
|
166
|
+
var AUTH_KEY = "__swr_login_user__";
|
|
167
|
+
function useUser() {
|
|
168
|
+
const { tokenManager, config } = useAuthContext();
|
|
169
|
+
const fetcher = async () => {
|
|
170
|
+
const token = tokenManager.getAccessToken();
|
|
171
|
+
if (!token) return null;
|
|
172
|
+
if (tokenManager.isExpired()) {
|
|
173
|
+
try {
|
|
174
|
+
await tokenManager.refresh();
|
|
175
|
+
} catch {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
if (config.fetchUser) {
|
|
180
|
+
const currentToken = tokenManager.getAccessToken();
|
|
181
|
+
if (!currentToken) return null;
|
|
182
|
+
return await config.fetchUser(currentToken);
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
};
|
|
186
|
+
const {
|
|
187
|
+
data,
|
|
188
|
+
error,
|
|
189
|
+
isLoading,
|
|
190
|
+
mutate: swrMutate
|
|
191
|
+
} = useSWR__default.default(AUTH_KEY, fetcher, {
|
|
192
|
+
revalidateOnFocus: true,
|
|
193
|
+
revalidateOnReconnect: true,
|
|
194
|
+
shouldRetryOnError: false
|
|
195
|
+
});
|
|
196
|
+
const mutate2 = async (newData) => {
|
|
197
|
+
if (newData === void 0) {
|
|
198
|
+
await swrMutate();
|
|
199
|
+
} else {
|
|
200
|
+
await swrMutate(newData, { revalidate: false });
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
return {
|
|
204
|
+
user: data ?? null,
|
|
205
|
+
isLoading,
|
|
206
|
+
isAuthenticated: !!data,
|
|
207
|
+
error,
|
|
208
|
+
mutate: mutate2
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
function useLogout() {
|
|
212
|
+
const { pluginManager, stateMachine, broadcastSync } = useAuthContext();
|
|
213
|
+
const [isLoading, setIsLoading] = react.useState(false);
|
|
214
|
+
const logout = react.useCallback(
|
|
215
|
+
async (options) => {
|
|
216
|
+
setIsLoading(true);
|
|
217
|
+
try {
|
|
218
|
+
await pluginManager.logout(options?.pluginName);
|
|
219
|
+
await useSWR.mutate(AUTH_KEY, null, { revalidate: false });
|
|
220
|
+
stateMachine.transition("unauthenticated");
|
|
221
|
+
const shouldBroadcast = options?.broadcast !== false;
|
|
222
|
+
if (shouldBroadcast && broadcastSync) {
|
|
223
|
+
broadcastSync.send("LOGOUT");
|
|
224
|
+
}
|
|
225
|
+
} catch (err) {
|
|
226
|
+
console.error("[swr-login] Logout error:", err);
|
|
227
|
+
await useSWR.mutate(AUTH_KEY, null, { revalidate: false });
|
|
228
|
+
stateMachine.transition("unauthenticated");
|
|
229
|
+
} finally {
|
|
230
|
+
setIsLoading(false);
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
[pluginManager, stateMachine, broadcastSync]
|
|
234
|
+
);
|
|
235
|
+
return { logout, isLoading };
|
|
236
|
+
}
|
|
237
|
+
function useSession() {
|
|
238
|
+
const { tokenManager } = useAuthContext();
|
|
239
|
+
return react.useMemo(() => {
|
|
240
|
+
const accessToken = tokenManager.getAccessToken();
|
|
241
|
+
const refreshToken = tokenManager.getRefreshToken();
|
|
242
|
+
const expiresAt = tokenManager.getAccessToken() ? tokenManager.getExpiresAt() : null;
|
|
243
|
+
return {
|
|
244
|
+
accessToken,
|
|
245
|
+
refreshToken,
|
|
246
|
+
expiresAt,
|
|
247
|
+
isExpired: core.isTokenExpired(expiresAt),
|
|
248
|
+
hasTokens: !!accessToken
|
|
249
|
+
};
|
|
250
|
+
}, [tokenManager]);
|
|
251
|
+
}
|
|
252
|
+
function usePermission() {
|
|
253
|
+
const { user } = useUser();
|
|
254
|
+
const hasPermission = react.useCallback(
|
|
255
|
+
(permission) => {
|
|
256
|
+
return user?.permissions?.includes(permission) ?? false;
|
|
257
|
+
},
|
|
258
|
+
[user]
|
|
259
|
+
);
|
|
260
|
+
const hasRole = react.useCallback(
|
|
261
|
+
(role) => {
|
|
262
|
+
return user?.roles?.includes(role) ?? false;
|
|
263
|
+
},
|
|
264
|
+
[user]
|
|
265
|
+
);
|
|
266
|
+
const hasAllPermissions = react.useCallback(
|
|
267
|
+
(permissions) => {
|
|
268
|
+
if (!user?.permissions) return false;
|
|
269
|
+
return permissions.every((p) => user.permissions?.includes(p));
|
|
270
|
+
},
|
|
271
|
+
[user]
|
|
272
|
+
);
|
|
273
|
+
const hasAnyPermission = react.useCallback(
|
|
274
|
+
(permissions) => {
|
|
275
|
+
if (!user?.permissions) return false;
|
|
276
|
+
return permissions.some((p) => user.permissions?.includes(p));
|
|
277
|
+
},
|
|
278
|
+
[user]
|
|
279
|
+
);
|
|
280
|
+
const hasAllRoles = react.useCallback(
|
|
281
|
+
(roles) => {
|
|
282
|
+
if (!user?.roles) return false;
|
|
283
|
+
return roles.every((r) => user.roles?.includes(r));
|
|
284
|
+
},
|
|
285
|
+
[user]
|
|
286
|
+
);
|
|
287
|
+
const hasAnyRole = react.useCallback(
|
|
288
|
+
(roles) => {
|
|
289
|
+
if (!user?.roles) return false;
|
|
290
|
+
return roles.some((r) => user.roles?.includes(r));
|
|
291
|
+
},
|
|
292
|
+
[user]
|
|
293
|
+
);
|
|
294
|
+
return {
|
|
295
|
+
hasPermission,
|
|
296
|
+
hasRole,
|
|
297
|
+
hasAllPermissions,
|
|
298
|
+
hasAnyPermission,
|
|
299
|
+
hasAllRoles,
|
|
300
|
+
hasAnyRole
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
function AuthGuard({
|
|
304
|
+
children,
|
|
305
|
+
permissions,
|
|
306
|
+
roles,
|
|
307
|
+
requireAll = false,
|
|
308
|
+
fallback = null,
|
|
309
|
+
loadingComponent = null
|
|
310
|
+
}) {
|
|
311
|
+
const { isLoading, isAuthenticated } = useUser();
|
|
312
|
+
const { hasAllPermissions, hasAnyPermission, hasAllRoles, hasAnyRole } = usePermission();
|
|
313
|
+
if (isLoading) {
|
|
314
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: loadingComponent });
|
|
315
|
+
}
|
|
316
|
+
if (!isAuthenticated) {
|
|
317
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
|
|
318
|
+
}
|
|
319
|
+
if (permissions && permissions.length > 0) {
|
|
320
|
+
const hasRequiredPermissions = requireAll ? hasAllPermissions(permissions) : hasAnyPermission(permissions);
|
|
321
|
+
if (!hasRequiredPermissions) {
|
|
322
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (roles && roles.length > 0) {
|
|
326
|
+
const hasRequiredRoles = requireAll ? hasAllRoles(roles) : hasAnyRole(roles);
|
|
327
|
+
if (!hasRequiredRoles) {
|
|
328
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: fallback });
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children });
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
exports.AUTH_KEY = AUTH_KEY;
|
|
335
|
+
exports.AuthGuard = AuthGuard;
|
|
336
|
+
exports.SWRLoginProvider = SWRLoginProvider;
|
|
337
|
+
exports.useAuthContext = useAuthContext;
|
|
338
|
+
exports.useLogin = useLogin;
|
|
339
|
+
exports.useLogout = useLogout;
|
|
340
|
+
exports.usePermission = usePermission;
|
|
341
|
+
exports.useSession = useSession;
|
|
342
|
+
exports.useUser = useUser;
|
|
343
|
+
//# sourceMappingURL=index.cjs.map
|
|
344
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/provider.tsx","../src/hooks/useLogin.ts","../src/hooks/useUser.ts","../src/hooks/useLogout.ts","../src/hooks/useSession.ts","../src/hooks/usePermission.ts","../src/components/AuthGuard.tsx"],"names":["createContext","useContext","useRef","useMemo","AuthEventEmitter","AuthStateMachine","TokenManager","PluginManager","BroadcastSync","useEffect","useState","useCallback","useSWR","mutate","isTokenExpired","jsx","Fragment"],"mappings":";;;;;;;;;;;;AAoBO,IAAM,WAAA,GAAcA,oBAAuC,IAAI,CAAA;AAO/D,SAAS,cAAA,GAAmC;AACjD,EAAA,MAAM,GAAA,GAAMC,iBAAW,WAAW,CAAA;AAClC,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,KAAA;AAAA,MACR;AAAA,KAEF;AAAA,EACF;AACA,EAAA,OAAO,GAAA;AACT;ACKO,SAAS,gBAAA,CAAiB,EAAE,MAAA,EAAQ,QAAA,EAAS,EAA0B;AAC5E,EAAA,MAAM,cAAA,GAAiBC,aAAO,KAAK,CAAA;AAEnC,EAAA,MAAM,YAAA,GAAeC,cAA0B,MAAM;AACnD,IAAA,MAAM,OAAA,GAAU,IAAIC,qBAAA,EAAiB;AACrC,IAAA,MAAM,YAAA,GAAe,IAAIC,qBAAA,CAAiB,OAAO,CAAA;AACjD,IAAA,MAAM,eAAe,IAAIC,iBAAA,CAAa,MAAA,CAAO,OAAA,EAAS,SAAS,YAAY,CAAA;AAC3E,IAAA,MAAM,aAAA,GAAgB,IAAIC,kBAAA,CAAc,YAAA,EAAc,OAAO,CAAA;AAG7D,IAAA,aAAA,CAAc,QAAA,CAAS,GAAG,MAAA,CAAO,OAAO,CAAA;AAGxC,IAAA,MAAM,UAAA,GAAa,MAAA,CAAO,QAAA,EAAU,mBAAA,KAAwB,KAAA;AAC5D,IAAA,MAAM,gBAAgB,UAAA,IAAc,OAAO,WAAW,WAAA,GAAc,IAAIC,oBAAc,GAAI,IAAA;AAG1F,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,OAAA,CAAQ,EAAA,CAAG,SAAS,CAAC,EAAE,MAAK,KAAM,MAAA,CAAO,OAAA,GAAU,IAAI,CAAC,CAAA;AAAA,IAC1D;AACA,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,OAAA,CAAQ,EAAA,CAAG,QAAA,EAAU,MAAM,MAAA,CAAO,YAAY,CAAA;AAAA,IAChD;AACA,IAAA,IAAI,OAAO,OAAA,EAAS;AAClB,MAAA,OAAA,CAAQ,EAAA,CAAG,SAAS,CAAC,EAAE,OAAM,KAAM,MAAA,CAAO,OAAA,GAAU,KAAK,CAAC,CAAA;AAAA,IAC5D;AAEA,IAAA,OAAO;AAAA,MACL,aAAA;AAAA,MACA,YAAA;AAAA,MACA,OAAA;AAAA,MACA,YAAA;AAAA,MACA,aAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA;AAGX,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,eAAe,OAAA,EAAS;AAC5B,IAAA,cAAA,CAAe,OAAA,GAAU,IAAA;AAEzB,IAAA,MAAM;AAAA,MACJ,aAAA;AAAA,MACA,aAAA;AAAA,MACA,YAAA;AAAA,MACA,YAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAA,EAAQ;AAAA,KACV,GAAI,YAAA;AAGJ,IAAA,aAAA,CAAc,aAAA,EAAc,CAAE,KAAA,CAAM,CAAC,GAAA,KAAQ;AAC3C,MAAA,OAAA,CAAQ,KAAA,CAAM,4CAA4C,GAAG,CAAA;AAAA,IAC/D,CAAC,CAAA;AAGD,IAAA,MAAM,aAAA,GAAgB,aAAa,cAAA,EAAe;AAClD,IAAA,IAAI,aAAA,IAAiB,CAAC,YAAA,CAAa,SAAA,EAAU,EAAG;AAC9C,MAAA,YAAA,CAAa,WAAW,eAAe,CAAA;AAAA,IACzC,CAAA,MAAA,IAAW,aAAA,IAAiB,YAAA,CAAa,SAAA,EAAU,EAAG;AACpD,MAAA,YAAA,CAAa,WAAW,iBAAiB,CAAA;AACzC,MAAA,OAAA,CAAQ,IAAA,CAAK,iBAAiB,MAAS,CAAA;AAAA,IACzC;AAGA,IAAA,IAAI,aAAA,EAAe;AACjB,MAAA,MAAM,WAAA,GAAc,aAAA,CAAc,SAAA,CAAU,CAAC,OAAA,KAAY;AACvD,QAAA,QAAQ,QAAQ,IAAA;AAAM,UACpB,KAAK,QAAA;AACH,YAAA,YAAA,CAAa,WAAA,EAAY;AACzB,YAAA,YAAA,CAAa,WAAW,iBAAiB,CAAA;AACzC,YAAA,OAAA,CAAQ,IAAA,CAAK,UAAU,MAAS,CAAA;AAChC,YAAA;AAAA,UACF,KAAK,OAAA;AAAA,UACL,KAAK,eAAA;AAEH,YAAA,IAAI,IAAI,YAAA,EAAc;AACpB,cAAA,GAAA,CAAI,aAAa,UAAA,EAAW;AAAA,YAC9B;AACA,YAAA;AAAA;AACJ,MACF,CAAC,CAAA;AAED,MAAA,OAAO,MAAM;AACX,QAAA,WAAA,EAAY;AACZ,QAAA,aAAA,CAAc,OAAA,EAAQ;AAAA,MACxB,CAAA;AAAA,IACF;AAAA,EACF,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAGjB,EAAAA,eAAA,CAAU,MAAM;AACd,IAAA,MAAM,EAAE,MAAA,EAAQ,GAAA,EAAK,YAAA,EAAc,YAAA,EAAc,SAAQ,GAAI,YAAA;AAE7D,IAAA,IAAI,CAAC,GAAA,CAAI,QAAA,EAAU,aAAA,IAAiB,OAAO,aAAa,WAAA,EAAa;AAErE,IAAA,IAAI,SAAA,GAAkD,IAAA;AAEtD,IAAA,MAAM,yBAAyB,MAAM;AACnC,MAAA,IAAI,SAAS,MAAA,EAAQ;AACnB,QAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,QAAA,EAAU,kBAAA,IAAsB,GAAA;AAClD,QAAA,SAAA,GAAY,WAAW,MAAM;AAC3B,UAAA,YAAA,CAAa,WAAA,EAAY;AACzB,UAAA,YAAA,CAAa,WAAW,iBAAiB,CAAA;AACzC,UAAA,OAAA,CAAQ,IAAA,CAAK,UAAU,MAAS,CAAA;AAAA,QAClC,GAAG,KAAK,CAAA;AAAA,MACV,CAAA,MAAO;AACL,QAAA,IAAI,SAAA,EAAW;AACb,UAAA,YAAA,CAAa,SAAS,CAAA;AACtB,UAAA,SAAA,GAAY,IAAA;AAAA,QACd;AAAA,MACF;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,gBAAA,CAAiB,oBAAoB,sBAAsB,CAAA;AACpE,IAAA,OAAO,MAAM;AACX,MAAA,QAAA,CAAS,mBAAA,CAAoB,oBAAoB,sBAAsB,CAAA;AACvE,MAAA,IAAI,SAAA,eAAwB,SAAS,CAAA;AAAA,IACvC,CAAA;AAAA,EACF,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AAEjB,EAAA,sCAAQ,WAAA,CAAY,QAAA,EAAZ,EAAqB,KAAA,EAAO,cAAe,QAAA,EAAS,CAAA;AAC9D;AC1HO,SAAS,SACd,UAAA,EAC8B;AAC9B,EAAA,MAAM,EAAE,aAAA,EAAe,YAAA,EAAc,MAAA,KAAW,cAAA,EAAe;AAC/D,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIC,eAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,KAAA,EAAO,QAAQ,CAAA,GAAIA,eAAuB,IAAI,CAAA;AAErD,EAAA,MAAM,KAAA,GAAQC,iBAAA;AAAA,IACZ,OACE,yBACA,gBAAA,KAC0B;AAC1B,MAAA,IAAI,cAAA;AACJ,MAAA,IAAI,mBAAA;AAEJ,MAAA,IAAI,OAAO,uBAAA,KAA4B,QAAA,IAAY,CAAC,UAAA,EAAY;AAC9D,QAAA,cAAA,GAAiB,uBAAA;AACjB,QAAA,mBAAA,GAAuB,oBAAoB,EAAC;AAAA,MAC9C,WAAW,UAAA,EAAY;AACrB,QAAA,cAAA,GAAiB,UAAA;AACjB,QAAA,mBAAA,GAAsB,uBAAA;AAAA,MACxB,CAAA,MAAO;AACL,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF;AAEA,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,QAAA,CAAS,IAAI,CAAA;AACb,MAAA,YAAA,CAAa,WAAW,gBAAgB,CAAA;AAExC,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,aAAA,CAAc,KAAA,CAAM,gBAAgB,mBAAmB,CAAA;AAC9E,QAAA,YAAA,CAAa,WAAW,eAAe,CAAA;AAGvC,QAAA,IAAI,OAAO,YAAA,EAAc;AACvB,UAAA,MAAM,MAAA,CAAO,YAAA,CAAa,OAAA,CAAQ,QAAA,CAAS,IAAI,CAAA;AAAA,QACjD;AAEA,QAAA,OAAO,QAAA;AAAA,MACT,SAAS,GAAA,EAAK;AACZ,QAAA,MAAM,YAAY,GAAA,YAAe,KAAA,GAAQ,GAAA,GAAM,IAAI,MAAM,cAAc,CAAA;AACvE,QAAA,QAAA,CAAS,SAAS,CAAA;AAClB,QAAA,YAAA,CAAa,WAAW,OAAO,CAAA;AAC/B,QAAA,MAAM,SAAA;AAAA,MACR,CAAA,SAAE;AACA,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,MACpB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,aAAA,EAAe,YAAA,EAAc,MAAA,EAAQ,UAAU;AAAA,GAClD;AAEA,EAAA,MAAM,KAAA,GAAQA,kBAAY,MAAM;AAC9B,IAAA,QAAA,CAAS,IAAI,CAAA;AAAA,EACf,CAAA,EAAG,EAAE,CAAA;AAEL,EAAA,OAAO,EAAE,KAAA,EAAO,SAAA,EAAW,KAAA,EAAO,KAAA,EAAM;AAC1C;AChGA,IAAM,QAAA,GAAW;AAmCV,SAAS,OAAA,GAAmD;AACjE,EAAA,MAAM,EAAE,YAAA,EAAc,MAAA,EAAO,GAAI,cAAA,EAAe;AAEhD,EAAA,MAAM,UAAU,YAA+B;AAC7C,IAAA,MAAM,KAAA,GAAQ,aAAa,cAAA,EAAe;AAC1C,IAAA,IAAI,CAAC,OAAO,OAAO,IAAA;AAEnB,IAAA,IAAI,YAAA,CAAa,WAAU,EAAG;AAC5B,MAAA,IAAI;AACF,QAAA,MAAM,aAAa,OAAA,EAAQ;AAAA,MAC7B,CAAA,CAAA,MAAQ;AACN,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF;AAEA,IAAA,IAAI,OAAO,SAAA,EAAW;AACpB,MAAA,MAAM,YAAA,GAAe,aAAa,cAAA,EAAe;AACjD,MAAA,IAAI,CAAC,cAAc,OAAO,IAAA;AAC1B,MAAA,OAAQ,MAAM,MAAA,CAAO,SAAA,CAAU,YAAY,CAAA;AAAA,IAC7C;AAEA,IAAA,OAAO,IAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM;AAAA,IACJ,IAAA;AAAA,IACA,KAAA;AAAA,IACA,SAAA;AAAA,IACA,MAAA,EAAQ;AAAA,GACV,GAAIC,uBAAA,CAAiB,QAAA,EAAU,OAAA,EAAS;AAAA,IACtC,iBAAA,EAAmB,IAAA;AAAA,IACnB,qBAAA,EAAuB,IAAA;AAAA,IACvB,kBAAA,EAAoB;AAAA,GACrB,CAAA;AAED,EAAA,MAAMC,OAAAA,GAAS,OAAO,OAAA,KAAsC;AAC1D,IAAA,IAAI,YAAY,MAAA,EAAW;AACzB,MAAA,MAAM,SAAA,EAAU;AAAA,IAClB,CAAA,MAAO;AACL,MAAA,MAAM,SAAA,CAAU,OAAA,EAAS,EAAE,UAAA,EAAY,OAAO,CAAA;AAAA,IAChD;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,MAAM,IAAA,IAAQ,IAAA;AAAA,IACd,SAAA;AAAA,IACA,eAAA,EAAiB,CAAC,CAAC,IAAA;AAAA,IACnB,KAAA;AAAA,IACA,MAAA,EAAAA;AAAA,GACF;AACF;ACnDO,SAAS,SAAA,GAA6B;AAC3C,EAAA,MAAM,EAAE,aAAA,EAAe,YAAA,EAAc,aAAA,KAAkB,cAAA,EAAe;AACtE,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIH,eAAS,KAAK,CAAA;AAEhD,EAAA,MAAM,MAAA,GAASC,iBAAAA;AAAA,IACb,OAAO,OAAA,KAA+B;AACpC,MAAA,YAAA,CAAa,IAAI,CAAA;AAEjB,MAAA,IAAI;AAEF,QAAA,MAAM,aAAA,CAAc,MAAA,CAAO,OAAA,EAAS,UAAU,CAAA;AAG9C,QAAA,MAAME,cAAO,QAAA,EAAU,IAAA,EAAM,EAAE,UAAA,EAAY,OAAO,CAAA;AAGlD,QAAA,YAAA,CAAa,WAAW,iBAAiB,CAAA;AAGzC,QAAA,MAAM,eAAA,GAAkB,SAAS,SAAA,KAAc,KAAA;AAC/C,QAAA,IAAI,mBAAmB,aAAA,EAAe;AACpC,UAAA,aAAA,CAAc,KAAK,QAAQ,CAAA;AAAA,QAC7B;AAAA,MACF,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,CAAQ,KAAA,CAAM,6BAA6B,GAAG,CAAA;AAE9C,QAAA,MAAMA,cAAO,QAAA,EAAU,IAAA,EAAM,EAAE,UAAA,EAAY,OAAO,CAAA;AAClD,QAAA,YAAA,CAAa,WAAW,iBAAiB,CAAA;AAAA,MAC3C,CAAA,SAAE;AACA,QAAA,YAAA,CAAa,KAAK,CAAA;AAAA,MACpB;AAAA,IACF,CAAA;AAAA,IACA,CAAC,aAAA,EAAe,YAAA,EAAc,aAAa;AAAA,GAC7C;AAEA,EAAA,OAAO,EAAE,QAAQ,SAAA,EAAU;AAC7B;ACxCO,SAAS,UAAA,GAA0B;AACxC,EAAA,MAAM,EAAE,YAAA,EAAa,GAAI,cAAA,EAAe;AAExC,EAAA,OAAOV,cAAQ,MAAM;AACnB,IAAA,MAAM,WAAA,GAAc,aAAa,cAAA,EAAe;AAChD,IAAA,MAAM,YAAA,GAAe,aAAa,eAAA,EAAgB;AAClD,IAAA,MAAM,YAAY,YAAA,CAAa,cAAA,EAAe,GAAI,YAAA,CAAa,cAAa,GAAI,IAAA;AAEhF,IAAA,OAAO;AAAA,MACL,WAAA;AAAA,MACA,YAAA;AAAA,MACA,SAAA;AAAA,MACA,SAAA,EAAWW,oBAAe,SAAS,CAAA;AAAA,MACnC,SAAA,EAAW,CAAC,CAAC;AAAA,KACf;AAAA,EACF,CAAA,EAAG,CAAC,YAAY,CAAC,CAAA;AACnB;ACdO,SAAS,aAAA,GAAqC;AACnD,EAAA,MAAM,EAAE,IAAA,EAAK,GAAI,OAAA,EAAQ;AAEzB,EAAA,MAAM,aAAA,GAAgBH,iBAAAA;AAAA,IACpB,CAAC,UAAA,KAAgC;AAC/B,MAAA,OAAO,IAAA,EAAM,WAAA,EAAa,QAAA,CAAS,UAAU,CAAA,IAAK,KAAA;AAAA,IACpD,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,OAAA,GAAUA,iBAAAA;AAAA,IACd,CAAC,IAAA,KAA0B;AACzB,MAAA,OAAO,IAAA,EAAM,KAAA,EAAO,QAAA,CAAS,IAAI,CAAA,IAAK,KAAA;AAAA,IACxC,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,iBAAA,GAAoBA,iBAAAA;AAAA,IACxB,CAAC,WAAA,KAAmC;AAClC,MAAA,IAAI,CAAC,IAAA,EAAM,WAAA,EAAa,OAAO,KAAA;AAC/B,MAAA,OAAO,WAAA,CAAY,MAAM,CAAC,CAAA,KAAM,KAAK,WAAA,EAAa,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IAC/D,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,gBAAA,GAAmBA,iBAAAA;AAAA,IACvB,CAAC,WAAA,KAAmC;AAClC,MAAA,IAAI,CAAC,IAAA,EAAM,WAAA,EAAa,OAAO,KAAA;AAC/B,MAAA,OAAO,WAAA,CAAY,KAAK,CAAC,CAAA,KAAM,KAAK,WAAA,EAAa,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IAC9D,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,WAAA,GAAcA,iBAAAA;AAAA,IAClB,CAAC,KAAA,KAA6B;AAC5B,MAAA,IAAI,CAAC,IAAA,EAAM,KAAA,EAAO,OAAO,KAAA;AACzB,MAAA,OAAO,KAAA,CAAM,MAAM,CAAC,CAAA,KAAM,KAAK,KAAA,EAAO,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IACnD,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,MAAM,UAAA,GAAaA,iBAAAA;AAAA,IACjB,CAAC,KAAA,KAA6B;AAC5B,MAAA,IAAI,CAAC,IAAA,EAAM,KAAA,EAAO,OAAO,KAAA;AACzB,MAAA,OAAO,KAAA,CAAM,KAAK,CAAC,CAAA,KAAM,KAAK,KAAA,EAAO,QAAA,CAAS,CAAC,CAAC,CAAA;AAAA,IAClD,CAAA;AAAA,IACA,CAAC,IAAI;AAAA,GACP;AAEA,EAAA,OAAO;AAAA,IACL,aAAA;AAAA,IACA,OAAA;AAAA,IACA,iBAAA;AAAA,IACA,gBAAA;AAAA,IACA,WAAA;AAAA,IACA;AAAA,GACF;AACF;AC3DO,SAAS,SAAA,CAAU;AAAA,EACxB,QAAA;AAAA,EACA,WAAA;AAAA,EACA,KAAA;AAAA,EACA,UAAA,GAAa,KAAA;AAAA,EACb,QAAA,GAAW,IAAA;AAAA,EACX,gBAAA,GAAmB;AACrB,CAAA,EAAmB;AACjB,EAAA,MAAM,EAAE,SAAA,EAAW,eAAA,EAAgB,GAAI,OAAA,EAAQ;AAC/C,EAAA,MAAM,EAAE,iBAAA,EAAmB,gBAAA,EAAkB,WAAA,EAAa,UAAA,KAAe,aAAA,EAAc;AAEvF,EAAA,IAAI,SAAA,EAAW;AACb,IAAA,uBAAOI,cAAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,gBAAA,EAAiB,CAAA;AAAA,EAC7B;AAEA,EAAA,IAAI,CAAC,eAAA,EAAiB;AACpB,IAAA,uBAAOD,cAAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,EACrB;AAGA,EAAA,IAAI,WAAA,IAAe,WAAA,CAAY,MAAA,GAAS,CAAA,EAAG;AACzC,IAAA,MAAM,yBAAyB,UAAA,GAC3B,iBAAA,CAAkB,WAAW,CAAA,GAC7B,iBAAiB,WAAW,CAAA;AAEhC,IAAA,IAAI,CAAC,sBAAA,EAAwB;AAC3B,MAAA,uBAAOD,cAAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,IACrB;AAAA,EACF;AAGA,EAAA,IAAI,KAAA,IAAS,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC7B,IAAA,MAAM,mBAAmB,UAAA,GAAa,WAAA,CAAY,KAAK,CAAA,GAAI,WAAW,KAAK,CAAA;AAE3E,IAAA,IAAI,CAAC,gBAAA,EAAkB;AACrB,MAAA,uBAAOD,cAAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAA,QAAA,EAAS,CAAA;AAAA,IACrB;AAAA,EACF;AAEA,EAAA,uBAAOD,cAAAA,CAAAC,mBAAA,EAAA,EAAG,QAAA,EAAS,CAAA;AACrB","file":"index.cjs","sourcesContent":["import type {\n AuthEventEmitter,\n AuthStateMachine,\n BroadcastSync,\n PluginManager,\n SWRLoginConfig,\n TokenManager,\n} from '@swr-login/core';\nimport { createContext, useContext } from 'react';\n\n/** Internal context value passed through SWRLoginProvider */\nexport interface AuthContextValue {\n pluginManager: PluginManager;\n tokenManager: TokenManager;\n emitter: AuthEventEmitter;\n stateMachine: AuthStateMachine;\n broadcastSync: BroadcastSync | null;\n config: SWRLoginConfig;\n}\n\nexport const AuthContext = createContext<AuthContextValue | null>(null);\n\n/**\n * Internal hook to access auth context.\n * Must be used within SWRLoginProvider.\n * @throws Error if used outside of SWRLoginProvider\n */\nexport function useAuthContext(): AuthContextValue {\n const ctx = useContext(AuthContext);\n if (!ctx) {\n throw new Error(\n '[swr-login] useAuthContext must be used within <SWRLoginProvider>. ' +\n 'Wrap your app with <SWRLoginProvider> to use swr-login hooks.',\n );\n }\n return ctx;\n}\n","import {\n AuthEventEmitter,\n AuthStateMachine,\n BroadcastSync,\n PluginManager,\n type SWRLoginConfig,\n TokenManager,\n} from '@swr-login/core';\nimport type React from 'react';\nimport { useEffect, useMemo, useRef } from 'react';\nimport { AuthContext, type AuthContextValue } from './context';\n\nexport interface SWRLoginProviderProps {\n /** Authentication configuration */\n config: SWRLoginConfig;\n children: React.ReactNode;\n}\n\n/**\n * SWRLoginProvider initializes the auth system and provides context to all child hooks.\n *\n * @example\n * ```tsx\n * import { SWRLoginProvider } from '@swr-login/react';\n * import { JWTAdapter } from '@swr-login/adapter-jwt';\n * import { PasswordPlugin } from '@swr-login/plugin-password';\n *\n * function App() {\n * return (\n * <SWRLoginProvider\n * config={{\n * adapter: JWTAdapter(),\n * plugins: [PasswordPlugin({ loginUrl: '/api/login' })],\n * }}\n * >\n * <YourApp />\n * </SWRLoginProvider>\n * );\n * }\n * ```\n */\nexport function SWRLoginProvider({ config, children }: SWRLoginProviderProps) {\n const initializedRef = useRef(false);\n\n const contextValue = useMemo<AuthContextValue>(() => {\n const emitter = new AuthEventEmitter();\n const stateMachine = new AuthStateMachine(emitter);\n const tokenManager = new TokenManager(config.adapter, emitter, stateMachine);\n const pluginManager = new PluginManager(tokenManager, emitter);\n\n // Register plugins\n pluginManager.register(...config.plugins);\n\n // Set up broadcast sync if enabled\n const enableSync = config.security?.enableBroadcastSync !== false;\n const broadcastSync = enableSync && typeof window !== 'undefined' ? new BroadcastSync() : null;\n\n // Wire up lifecycle callbacks\n if (config.onLogin) {\n emitter.on('login', ({ user }) => config.onLogin?.(user));\n }\n if (config.onLogout) {\n emitter.on('logout', () => config.onLogout?.());\n }\n if (config.onError) {\n emitter.on('error', ({ error }) => config.onError?.(error));\n }\n\n return {\n pluginManager,\n tokenManager,\n emitter,\n stateMachine,\n broadcastSync,\n config,\n };\n }, [config]);\n\n // Initialize plugins and broadcast sync on mount\n useEffect(() => {\n if (initializedRef.current) return;\n initializedRef.current = true;\n\n const {\n pluginManager,\n broadcastSync,\n tokenManager,\n stateMachine,\n emitter,\n config: cfg,\n } = contextValue;\n\n // Initialize all plugins\n pluginManager.initializeAll().catch((err) => {\n console.error('[swr-login] Plugin initialization error:', err);\n });\n\n // Check if user has existing token -> restore session\n const existingToken = tokenManager.getAccessToken();\n if (existingToken && !tokenManager.isExpired()) {\n stateMachine.transition('authenticated');\n } else if (existingToken && tokenManager.isExpired()) {\n stateMachine.transition('unauthenticated');\n emitter.emit('token-expired', undefined);\n }\n\n // Listen for cross-tab events\n if (broadcastSync) {\n const unsubscribe = broadcastSync.onMessage((message) => {\n switch (message.type) {\n case 'LOGOUT':\n tokenManager.clearTokens();\n stateMachine.transition('unauthenticated');\n emitter.emit('logout', undefined);\n break;\n case 'LOGIN':\n case 'TOKEN_REFRESH':\n // Trigger revalidation from other tab\n if (cfg.cacheAdapter) {\n cfg.cacheAdapter.revalidate();\n }\n break;\n }\n });\n\n return () => {\n unsubscribe();\n broadcastSync.destroy();\n };\n }\n }, [contextValue]);\n\n // Visibility change handler for security\n useEffect(() => {\n const { config: cfg, tokenManager, stateMachine, emitter } = contextValue;\n\n if (!cfg.security?.clearOnHidden || typeof document === 'undefined') return;\n\n let timeoutId: ReturnType<typeof setTimeout> | null = null;\n\n const handleVisibilityChange = () => {\n if (document.hidden) {\n const delay = cfg.security?.clearOnHiddenDelay ?? 300_000;\n timeoutId = setTimeout(() => {\n tokenManager.clearTokens();\n stateMachine.transition('unauthenticated');\n emitter.emit('logout', undefined);\n }, delay);\n } else {\n if (timeoutId) {\n clearTimeout(timeoutId);\n timeoutId = null;\n }\n }\n };\n\n document.addEventListener('visibilitychange', handleVisibilityChange);\n return () => {\n document.removeEventListener('visibilitychange', handleVisibilityChange);\n if (timeoutId) clearTimeout(timeoutId);\n };\n }, [contextValue]);\n\n return <AuthContext.Provider value={contextValue}>{children}</AuthContext.Provider>;\n}\n","import type { AuthResponse } from '@swr-login/core';\nimport { useCallback, useState } from 'react';\nimport { useAuthContext } from '../context';\n\nexport interface UseLoginOptions {\n /** Plugin name to use for login */\n pluginName?: string;\n}\n\nexport interface UseLoginReturn<TCredentials = unknown> {\n /**\n * Trigger login with specified credentials.\n * If pluginName was not provided in options, it must be passed as first argument.\n */\n login: (\n credentialsOrPluginName: TCredentials | string,\n credentials?: TCredentials,\n ) => Promise<AuthResponse>;\n /** Whether a login request is in progress */\n isLoading: boolean;\n /** Last login error, if any */\n error: Error | null;\n /** Reset error state */\n reset: () => void;\n}\n\n/**\n * Hook to trigger login flow via a registered plugin.\n *\n * @param pluginName - Optional default plugin name\n *\n * @example\n * ```tsx\n * // With default plugin\n * const { login, isLoading, error } = useLogin('password');\n * await login({ username: 'alice', password: 'secret' });\n *\n * // Without default plugin (specify at call time)\n * const { login } = useLogin();\n * await login('oauth-google', { redirect: false });\n * ```\n */\nexport function useLogin<TCredentials = unknown>(\n pluginName?: string,\n): UseLoginReturn<TCredentials> {\n const { pluginManager, stateMachine, config } = useAuthContext();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const login = useCallback(\n async (\n credentialsOrPluginName: TCredentials | string,\n maybeCredentials?: TCredentials,\n ): Promise<AuthResponse> => {\n let resolvedPlugin: string;\n let resolvedCredentials: TCredentials;\n\n if (typeof credentialsOrPluginName === 'string' && !pluginName) {\n resolvedPlugin = credentialsOrPluginName;\n resolvedCredentials = (maybeCredentials ?? {}) as TCredentials;\n } else if (pluginName) {\n resolvedPlugin = pluginName;\n resolvedCredentials = credentialsOrPluginName as TCredentials;\n } else {\n throw new Error(\n '[swr-login] Plugin name is required. Provide it to useLogin() or login().',\n );\n }\n\n setIsLoading(true);\n setError(null);\n stateMachine.transition('authenticating');\n\n try {\n const response = await pluginManager.login(resolvedPlugin, resolvedCredentials);\n stateMachine.transition('authenticated');\n\n // Update cache adapter if available\n if (config.cacheAdapter) {\n await config.cacheAdapter.setUser(response.user);\n }\n\n return response;\n } catch (err) {\n const authError = err instanceof Error ? err : new Error('Login failed');\n setError(authError);\n stateMachine.transition('error');\n throw authError;\n } finally {\n setIsLoading(false);\n }\n },\n [pluginManager, stateMachine, config, pluginName],\n );\n\n const reset = useCallback(() => {\n setError(null);\n }, []);\n\n return { login, isLoading, error, reset };\n}\n","import type { User } from '@swr-login/core';\nimport useSWR from 'swr';\nimport { useAuthContext } from '../context';\n\nconst AUTH_KEY = '__swr_login_user__';\n\nexport interface UseUserReturn<T extends User = User> {\n /** Current authenticated user, or null if not logged in */\n user: T | null;\n /** Whether user data is being fetched */\n isLoading: boolean;\n /** Whether user is authenticated */\n isAuthenticated: boolean;\n /** Error from fetching user data */\n error: Error | undefined;\n /**\n * Manually update cached user data.\n * Call with `null` to clear, or with a user object to update.\n */\n mutate: (data?: T | null) => Promise<void>;\n}\n\n/**\n * Hook to access current user data via SWR cache.\n *\n * Uses SWR's stale-while-revalidate strategy:\n * - Immediately returns cached user data\n * - Revalidates in the background using the configured fetchUser function\n * - Automatically syncs across all components using this hook\n *\n * @example\n * ```tsx\n * const { user, isLoading, isAuthenticated } = useUser<MyUser>();\n *\n * if (isLoading) return <Spinner />;\n * if (!isAuthenticated) return <LoginPage />;\n * return <Dashboard user={user} />;\n * ```\n */\nexport function useUser<T extends User = User>(): UseUserReturn<T> {\n const { tokenManager, config } = useAuthContext();\n\n const fetcher = async (): Promise<T | null> => {\n const token = tokenManager.getAccessToken();\n if (!token) return null;\n\n if (tokenManager.isExpired()) {\n try {\n await tokenManager.refresh();\n } catch {\n return null;\n }\n }\n\n if (config.fetchUser) {\n const currentToken = tokenManager.getAccessToken();\n if (!currentToken) return null;\n return (await config.fetchUser(currentToken)) as T;\n }\n\n return null;\n };\n\n const {\n data,\n error,\n isLoading,\n mutate: swrMutate,\n } = useSWR<T | null>(AUTH_KEY, fetcher, {\n revalidateOnFocus: true,\n revalidateOnReconnect: true,\n shouldRetryOnError: false,\n });\n\n const mutate = async (newData?: T | null): Promise<void> => {\n if (newData === undefined) {\n await swrMutate();\n } else {\n await swrMutate(newData, { revalidate: false });\n }\n };\n\n return {\n user: data ?? null,\n isLoading,\n isAuthenticated: !!data,\n error,\n mutate,\n };\n}\n\n/** SWR cache key used for user data. Exported for advanced usage. */\nexport { AUTH_KEY };\n","import { useCallback, useState } from 'react';\nimport { mutate } from 'swr';\nimport { useAuthContext } from '../context';\nimport { AUTH_KEY } from './useUser';\n\nexport interface UseLogoutOptions {\n /** Specific plugin to call logout on */\n pluginName?: string;\n /** Whether to broadcast logout to other tabs (default: true) */\n broadcast?: boolean;\n}\n\nexport interface UseLogoutReturn {\n /** Execute logout */\n logout: (options?: UseLogoutOptions) => Promise<void>;\n /** Whether logout is in progress */\n isLoading: boolean;\n}\n\n/**\n * Hook to perform secure logout with cross-tab sync.\n *\n * Logout flow:\n * 1. Call plugin logout (if applicable)\n * 2. Clear stored tokens\n * 3. Clear SWR cache (mutate user to null)\n * 4. Broadcast logout to other tabs\n * 5. Transition state to 'unauthenticated'\n *\n * @example\n * ```tsx\n * const { logout, isLoading } = useLogout();\n *\n * <button onClick={() => logout()} disabled={isLoading}>\n * Sign Out\n * </button>\n * ```\n */\nexport function useLogout(): UseLogoutReturn {\n const { pluginManager, stateMachine, broadcastSync } = useAuthContext();\n const [isLoading, setIsLoading] = useState(false);\n\n const logout = useCallback(\n async (options?: UseLogoutOptions) => {\n setIsLoading(true);\n\n try {\n // Call plugin logout\n await pluginManager.logout(options?.pluginName);\n\n // Clear SWR cache\n await mutate(AUTH_KEY, null, { revalidate: false });\n\n // Update state\n stateMachine.transition('unauthenticated');\n\n // Broadcast to other tabs\n const shouldBroadcast = options?.broadcast !== false;\n if (shouldBroadcast && broadcastSync) {\n broadcastSync.send('LOGOUT');\n }\n } catch (err) {\n console.error('[swr-login] Logout error:', err);\n // Even if logout API fails, clear local state\n await mutate(AUTH_KEY, null, { revalidate: false });\n stateMachine.transition('unauthenticated');\n } finally {\n setIsLoading(false);\n }\n },\n [pluginManager, stateMachine, broadcastSync],\n );\n\n return { logout, isLoading };\n}\n","import { isTokenExpired } from '@swr-login/core';\nimport { useMemo } from 'react';\nimport { useAuthContext } from '../context';\n\nexport interface SessionInfo {\n /** Current access token */\n accessToken: string | null;\n /** Current refresh token */\n refreshToken: string | null;\n /** Token expiration timestamp (ms since epoch) */\n expiresAt: number | null;\n /** Whether the access token has expired */\n isExpired: boolean;\n /** Whether tokens exist (regardless of expiry) */\n hasTokens: boolean;\n}\n\n/**\n * Hook to access raw session/token information.\n *\n * Useful for:\n * - Adding Authorization headers to custom requests\n * - Checking token expiry status\n * - Debugging session state\n *\n * @example\n * ```tsx\n * const { accessToken, isExpired } = useSession();\n *\n * const fetchData = () => fetch('/api/data', {\n * headers: { Authorization: `Bearer ${accessToken}` },\n * });\n * ```\n */\nexport function useSession(): SessionInfo {\n const { tokenManager } = useAuthContext();\n\n return useMemo(() => {\n const accessToken = tokenManager.getAccessToken();\n const refreshToken = tokenManager.getRefreshToken();\n const expiresAt = tokenManager.getAccessToken() ? tokenManager.getExpiresAt() : null;\n\n return {\n accessToken,\n refreshToken,\n expiresAt,\n isExpired: isTokenExpired(expiresAt),\n hasTokens: !!accessToken,\n };\n }, [tokenManager]);\n}\n","import { useCallback } from 'react';\nimport { useUser } from './useUser';\n\nexport interface UsePermissionReturn {\n /** Check if user has a specific permission */\n hasPermission: (permission: string) => boolean;\n /** Check if user has a specific role */\n hasRole: (role: string) => boolean;\n /** Check if user has all specified permissions */\n hasAllPermissions: (permissions: string[]) => boolean;\n /** Check if user has any of the specified permissions */\n hasAnyPermission: (permissions: string[]) => boolean;\n /** Check if user has all specified roles */\n hasAllRoles: (roles: string[]) => boolean;\n /** Check if user has any of the specified roles */\n hasAnyRole: (roles: string[]) => boolean;\n}\n\n/**\n * Hook for checking user permissions and roles.\n *\n * Reads from the `permissions` and `roles` arrays on the User object.\n *\n * @example\n * ```tsx\n * const { hasPermission, hasRole } = usePermission();\n *\n * if (hasPermission('admin:write')) {\n * // Show admin controls\n * }\n *\n * if (hasRole('editor')) {\n * // Show editor tools\n * }\n * ```\n */\nexport function usePermission(): UsePermissionReturn {\n const { user } = useUser();\n\n const hasPermission = useCallback(\n (permission: string): boolean => {\n return user?.permissions?.includes(permission) ?? false;\n },\n [user],\n );\n\n const hasRole = useCallback(\n (role: string): boolean => {\n return user?.roles?.includes(role) ?? false;\n },\n [user],\n );\n\n const hasAllPermissions = useCallback(\n (permissions: string[]): boolean => {\n if (!user?.permissions) return false;\n return permissions.every((p) => user.permissions?.includes(p));\n },\n [user],\n );\n\n const hasAnyPermission = useCallback(\n (permissions: string[]): boolean => {\n if (!user?.permissions) return false;\n return permissions.some((p) => user.permissions?.includes(p));\n },\n [user],\n );\n\n const hasAllRoles = useCallback(\n (roles: string[]): boolean => {\n if (!user?.roles) return false;\n return roles.every((r) => user.roles?.includes(r));\n },\n [user],\n );\n\n const hasAnyRole = useCallback(\n (roles: string[]): boolean => {\n if (!user?.roles) return false;\n return roles.some((r) => user.roles?.includes(r));\n },\n [user],\n );\n\n return {\n hasPermission,\n hasRole,\n hasAllPermissions,\n hasAnyPermission,\n hasAllRoles,\n hasAnyRole,\n };\n}\n","import type React from 'react';\nimport { usePermission } from '../hooks/usePermission';\nimport { useUser } from '../hooks/useUser';\n\nexport interface AuthGuardProps {\n children: React.ReactNode;\n /** Required permissions (checked against user.permissions) */\n permissions?: string[];\n /** Required roles (checked against user.roles) */\n roles?: string[];\n /** If true, ALL permissions/roles must match. If false, ANY match suffices. (default: false) */\n requireAll?: boolean;\n /** Component to render when user is not authenticated or lacks permissions */\n fallback?: React.ReactNode;\n /** Component to render while checking auth status */\n loadingComponent?: React.ReactNode;\n}\n\n/**\n * Declarative auth guard component.\n * Protects child content based on authentication state and permissions/roles.\n *\n * @example\n * ```tsx\n * <AuthGuard\n * permissions={['admin', 'editor']}\n * requireAll={false}\n * fallback={<Navigate to=\"/login\" />}\n * loadingComponent={<Skeleton />}\n * >\n * <AdminPanel />\n * </AuthGuard>\n * ```\n */\nexport function AuthGuard({\n children,\n permissions,\n roles,\n requireAll = false,\n fallback = null,\n loadingComponent = null,\n}: AuthGuardProps) {\n const { isLoading, isAuthenticated } = useUser();\n const { hasAllPermissions, hasAnyPermission, hasAllRoles, hasAnyRole } = usePermission();\n\n if (isLoading) {\n return <>{loadingComponent}</>;\n }\n\n if (!isAuthenticated) {\n return <>{fallback}</>;\n }\n\n // Check permissions\n if (permissions && permissions.length > 0) {\n const hasRequiredPermissions = requireAll\n ? hasAllPermissions(permissions)\n : hasAnyPermission(permissions);\n\n if (!hasRequiredPermissions) {\n return <>{fallback}</>;\n }\n }\n\n // Check roles\n if (roles && roles.length > 0) {\n const hasRequiredRoles = requireAll ? hasAllRoles(roles) : hasAnyRole(roles);\n\n if (!hasRequiredRoles) {\n return <>{fallback}</>;\n }\n }\n\n return <>{children}</>;\n}\n"]}
|