@shane_donnelly/dsi-internal-react-utils 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -8,10 +8,16 @@ Librairie de composants et utilitaires React pour les projets front-end de la DS
8
8
  npm install @shane_donnelly/dsi-internal-react-utils keycloak-js
9
9
  ```
10
10
 
11
+ ### Styles
12
+
13
+ L'import du CSS est obligatoire pour charger les styles des composants :
14
+
15
+ ```ts
16
+ import '@shane_donnelly/dsi-internal-react-utils/style.css'
17
+ ```
18
+
11
19
  ### Prérequis
12
20
 
13
- - React >= 19
14
- - keycloak-js >= 25
15
21
  - Un serveur Keycloak configuré avec un realm, un client, et au moins un Identity Provider
16
22
 
17
23
  > **Recommandé** : utiliser [react-router](https://reactrouter.com/) pour éviter de perdre l'état de la page lors des redirections d'authentification.
@@ -159,3 +165,47 @@ function AdvancedComponent() {
159
165
  console.log(keycloak?.tokenParsed);
160
166
  }
161
167
  ```
168
+
169
+ ### Fonctions utilitaires standalone
170
+
171
+ Deux fonctions sont disponibles pour manipuler l'instance Keycloak en dehors de React (intercepteurs HTTP, services, etc.) :
172
+
173
+ ```tsx
174
+ import { useAuth, logoutKeycloak, refreshTokenKeycloak } from '@shane_donnelly/dsi-internal-react-utils';
175
+
176
+ // Récupérer l'instance keycloak via useAuth()
177
+ const { keycloak } = useAuth();
178
+
179
+ // Rafraîchir le token (minValidity en secondes, défaut: 30)
180
+ const refreshed = await refreshTokenKeycloak(keycloak!, 60);
181
+ const freshToken = keycloak!.token;
182
+
183
+ // Déconnecter l'utilisateur (redirectUri optionnel, défaut: window.location.origin)
184
+ await logoutKeycloak(keycloak!);
185
+ ```
186
+
187
+ Exemple dans un intercepteur Axios :
188
+
189
+ ```ts
190
+ import axios from 'axios';
191
+ import { logoutKeycloak, refreshTokenKeycloak } from '@shane_donnelly/dsi-internal-react-utils';
192
+ import type Keycloak from 'keycloak-js';
193
+
194
+ function setupInterceptors(keycloak: Keycloak) {
195
+ axios.interceptors.request.use(async (config) => {
196
+ await refreshTokenKeycloak(keycloak, 60);
197
+ config.headers.Authorization = `Bearer ${keycloak.token}`;
198
+ return config;
199
+ });
200
+
201
+ axios.interceptors.response.use(
202
+ (response) => response,
203
+ async (error) => {
204
+ if (error.response?.status === 401) {
205
+ await logoutKeycloak(keycloak);
206
+ }
207
+ return Promise.reject(error);
208
+ },
209
+ );
210
+ }
211
+ ```
@@ -2,7 +2,7 @@ import { KeycloakProvider as e } from "./keycloak/react/KeycloakProvider/index.j
2
2
  import { useAuth as t } from "./keycloak/react/hooks/useAuth.js";
3
3
  import { useEffect as n, useRef as r } from "react";
4
4
  import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
5
- import './assets/ProtectedRoute.css';var s = {
5
+ var s = {
6
6
  loadingContainer: "_loadingContainer_1th3z_1",
7
7
  spinner: "_spinner_1th3z_11",
8
8
  spin: "_spin_1th3z_11",
@@ -20,3 +20,41 @@ export declare function initKeycloak(keycloak: Keycloak): Promise<boolean>;
20
20
  * @returns Informations utilisateur ou `null`
21
21
  */
22
22
  export declare function parseUser(keycloak: Keycloak): AuthUser | null;
23
+ /**
24
+ * Déconnecte l'utilisateur via l'instance Keycloak.
25
+ *
26
+ * Utilisable en dehors de React (ex: intercepteur HTTP, service, guard).
27
+ *
28
+ * @param keycloak - Instance Keycloak (récupérable via `useAuth().keycloak`)
29
+ * @param redirectUri - URL de redirection après déconnexion (défaut: `window.location.origin`)
30
+ *
31
+ * @example
32
+ * ```ts
33
+ * import { logoutKeycloak } from '@shane_donnelly/dsi-internal-react-utils';
34
+ *
35
+ * // dans un intercepteur axios
36
+ * if (response.status === 401) {
37
+ * await logoutKeycloak(keycloakInstance);
38
+ * }
39
+ * ```
40
+ */
41
+ export declare function logoutKeycloak(keycloak: Keycloak, redirectUri?: string): Promise<void>;
42
+ /**
43
+ * Rafraîchit le token d'accès via l'instance Keycloak.
44
+ *
45
+ * Utilisable en dehors de React (ex: intercepteur HTTP, service).
46
+ *
47
+ * @param keycloak - Instance Keycloak (récupérable via `useAuth().keycloak`)
48
+ * @param minValidity - Durée minimale de validité restante en secondes (défaut: 30)
49
+ * @returns `true` si le token a été rafraîchi, `false` sinon
50
+ *
51
+ * @example
52
+ * ```ts
53
+ * import { refreshTokenKeycloak } from '@shane_donnelly/dsi-internal-react-utils';
54
+ *
55
+ * // avant un appel API
56
+ * await refreshTokenKeycloak(keycloakInstance, 60);
57
+ * const token = keycloakInstance.token;
58
+ * ```
59
+ */
60
+ export declare function refreshTokenKeycloak(keycloak: Keycloak, minValidity?: number): Promise<boolean>;
@@ -21,5 +21,15 @@ async function n(e) {
21
21
  function r(e) {
22
22
  return e.tokenParsed ? e.tokenParsed : null;
23
23
  }
24
+ async function i(e, t) {
25
+ await e.logout({ redirectUri: t ?? window.location.origin });
26
+ }
27
+ async function a(e, t = 30) {
28
+ try {
29
+ return await e.updateToken(t);
30
+ } catch (e) {
31
+ return console.warn("[dsi-keycloak] Token refresh failed:", e), !1;
32
+ }
33
+ }
24
34
  //#endregion
25
- export { t as createKeycloakInstance, n as initKeycloak, r as parseUser };
35
+ export { t as createKeycloakInstance, n as initKeycloak, i as logoutKeycloak, r as parseUser, a as refreshTokenKeycloak };
@@ -3,4 +3,5 @@ export type { KeycloakProviderProps } from './react/KeycloakProvider';
3
3
  export { ProtectedRoute } from './react/ProtectedRoute';
4
4
  export type { ProtectedRouteProps } from './react/ProtectedRoute';
5
5
  export { useAuth } from './react/hooks/useAuth';
6
+ export { logoutKeycloak, refreshTokenKeycloak } from './core/client';
6
7
  export type { KeycloakConfig, KeycloakAuthOptions, AuthStatus, AuthUser, AuthContextValue, } from './core/types';
@@ -1,4 +1,5 @@
1
- import { KeycloakProvider as e } from "./react/KeycloakProvider/index.js";
2
- import { useAuth as t } from "./react/hooks/useAuth.js";
3
- import { t as n } from "../ProtectedRoute-Bl0cCdQ2.js";
4
- export { e as KeycloakProvider, n as ProtectedRoute, t as useAuth };
1
+ import { logoutKeycloak as e, refreshTokenKeycloak as t } from "./core/client.js";
2
+ import { KeycloakProvider as n } from "./react/KeycloakProvider/index.js";
3
+ import { useAuth as r } from "./react/hooks/useAuth.js";
4
+ import { t as i } from "../ProtectedRoute-_48urWWd.js";
5
+ export { n as KeycloakProvider, i as ProtectedRoute, e as logoutKeycloak, t as refreshTokenKeycloak, r as useAuth };
@@ -1,2 +1,2 @@
1
- import { t as e } from "../../../ProtectedRoute-Bl0cCdQ2.js";
1
+ import { t as e } from "../../../ProtectedRoute-_48urWWd.js";
2
2
  export { e as ProtectedRoute };
package/dist/main.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export { KeycloakProvider, ProtectedRoute, useAuth, } from './keycloak';
1
+ export { KeycloakProvider, ProtectedRoute, useAuth, logoutKeycloak, refreshTokenKeycloak, } from './keycloak';
2
2
  export type { KeycloakProviderProps, ProtectedRouteProps, KeycloakConfig, KeycloakAuthOptions, AuthStatus, AuthUser, AuthContextValue, } from './keycloak';
package/dist/main.js CHANGED
@@ -1,5 +1,6 @@
1
- import { KeycloakProvider as e } from "./keycloak/react/KeycloakProvider/index.js";
2
- import { useAuth as t } from "./keycloak/react/hooks/useAuth.js";
3
- import { t as n } from "./ProtectedRoute-Bl0cCdQ2.js";
1
+ import { logoutKeycloak as e, refreshTokenKeycloak as t } from "./keycloak/core/client.js";
2
+ import { KeycloakProvider as n } from "./keycloak/react/KeycloakProvider/index.js";
3
+ import { useAuth as r } from "./keycloak/react/hooks/useAuth.js";
4
+ import { t as i } from "./ProtectedRoute-_48urWWd.js";
4
5
  import "./keycloak/index.js";
5
- export { e as KeycloakProvider, n as ProtectedRoute, t as useAuth };
6
+ export { n as KeycloakProvider, i as ProtectedRoute, e as logoutKeycloak, t as refreshTokenKeycloak, r as useAuth };
@@ -1 +1,2 @@
1
1
  ._loadingContainer_1th3z_1{flex-direction:column;justify-content:center;align-items:center;gap:1rem;min-height:100vh;font-family:system-ui,-apple-system,sans-serif;display:flex}._spinner_1th3z_11{border:3px solid #e5e7eb;border-top-color:#3b82f6;border-radius:50%;width:40px;height:40px;animation:1s linear infinite _spin_1th3z_11}@keyframes _spin_1th3z_11{to{transform:rotate(360deg)}}._errorContainer_1th3z_26{flex-direction:column;justify-content:center;align-items:center;gap:1rem;min-height:100vh;font-family:system-ui,-apple-system,sans-serif;display:flex}._errorMessage_1th3z_36{color:#dc2626;text-align:center;background:#fef2f2;border-radius:12px;max-width:400px;padding:1.5rem}
2
+ /*$vite$:1*/
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@shane_donnelly/dsi-internal-react-utils",
3
3
  "private": false,
4
- "version": "0.1.0",
4
+ "version": "0.1.2",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -33,12 +33,16 @@
33
33
  },
34
34
  "main": "dist/main.js",
35
35
  "types": "dist/main.d.ts",
36
+ "exports": {
37
+ ".": {
38
+ "import": "./dist/main.js",
39
+ "types": "./dist/main.d.ts"
40
+ },
41
+ "./style.css": "./dist/style.css"
42
+ },
36
43
  "files": [
37
44
  "dist"
38
45
  ],
39
- "sideEffects": [
40
- "**/*.css"
41
- ],
42
46
  "peerDependencies": {
43
47
  "react": "^19.2.4",
44
48
  "react-dom": "^19.2.4",