@shane_donnelly/dsi-internal-react-utils 0.0.1 → 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/README.md CHANGED
@@ -1,4 +1,161 @@
1
- ### Librairie de composants React pour les différents projet de la DSI
1
+ # @shane_donnelly/dsi-internal-react-utils
2
2
 
3
- Actuellement, les composants sont des exemples.
3
+ Librairie de composants et utilitaires React pour les projets front-end de la DSI.
4
4
 
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @shane_donnelly/dsi-internal-react-utils keycloak-js
9
+ ```
10
+
11
+ ### Prérequis
12
+
13
+ - React >= 19
14
+ - keycloak-js >= 25
15
+ - Un serveur Keycloak configuré avec un realm, un client, et au moins un Identity Provider
16
+
17
+ > **Recommandé** : utiliser [react-router](https://reactrouter.com/) pour éviter de perdre l'état de la page lors des redirections d'authentification.
18
+
19
+ ## Modules
20
+
21
+ ### Keycloak
22
+
23
+ Wrapper de simplification pour `keycloak-js`. Gère l'authentification automatique via Identity Provider, le refresh de token, et la protection de routes/zones.
24
+
25
+ [Documentation complète du module Keycloak](docs/keycloak.md)
26
+
27
+ ---
28
+
29
+ ## Exemple complet avec React Router
30
+
31
+ ```tsx
32
+ // main.tsx
33
+ import React from 'react';
34
+ import ReactDOM from 'react-dom/client';
35
+ import { BrowserRouter } from 'react-router-dom';
36
+ import App from './App';
37
+
38
+ ReactDOM.createRoot(document.getElementById('root')!).render(
39
+ <React.StrictMode>
40
+ <BrowserRouter>
41
+ <App />
42
+ </BrowserRouter>
43
+ </React.StrictMode>,
44
+ );
45
+ ```
46
+
47
+ ```tsx
48
+ // App.tsx
49
+ import { Routes, Route } from 'react-router-dom';
50
+ import { KeycloakProvider, ProtectedRoute } from '@shane_donnelly/dsi-internal-react-utils';
51
+ import PublicPage from './pages/PublicPage';
52
+ import Dashboard from './pages/Dashboard';
53
+ import Profile from './pages/Profile';
54
+
55
+ const keycloakConfig = {
56
+ url: 'https://keycloak.example.com',
57
+ realm: 'my-realm',
58
+ clientId: 'my-frontend',
59
+ };
60
+
61
+ export default function App() {
62
+ return (
63
+ <KeycloakProvider config={keycloakConfig} idpHint="oidc" refreshInterval={300}>
64
+ <Routes>
65
+ {/* Route publique — accessible sans authentification */}
66
+ <Route path="/" element={<PublicPage />} />
67
+
68
+ {/* Routes protégées — redirection automatique vers l'IDP */}
69
+ <Route
70
+ path="/dashboard"
71
+ element={
72
+ <ProtectedRoute>
73
+ <Dashboard />
74
+ </ProtectedRoute>
75
+ }
76
+ />
77
+ <Route
78
+ path="/profile"
79
+ element={
80
+ <ProtectedRoute fallback={<p>Chargement du profil...</p>}>
81
+ <Profile />
82
+ </ProtectedRoute>
83
+ }
84
+ />
85
+ </Routes>
86
+ </KeycloakProvider>
87
+ );
88
+ }
89
+ ```
90
+
91
+ ```tsx
92
+ // pages/Dashboard.tsx
93
+ import { useAuth } from '@shane_donnelly/dsi-internal-react-utils';
94
+
95
+ export default function Dashboard() {
96
+ const { user, token, logout } = useAuth();
97
+
98
+ return (
99
+ <div>
100
+ <h1>Bienvenue {user?.name}</h1>
101
+ <p>Email : {user?.email}</p>
102
+ <button onClick={() => logout()}>Se déconnecter</button>
103
+ </div>
104
+ );
105
+ }
106
+ ```
107
+
108
+ ### Mode plug & play (sans Provider)
109
+
110
+ Pour un usage rapide sans `KeycloakProvider`, passez `config` directement à `ProtectedRoute` :
111
+
112
+ ```tsx
113
+ import { ProtectedRoute } from '@shane_donnelly/dsi-internal-react-utils';
114
+
115
+ function App() {
116
+ return (
117
+ <ProtectedRoute
118
+ config={{
119
+ url: 'https://keycloak.example.com',
120
+ realm: 'my-realm',
121
+ clientId: 'my-frontend',
122
+ }}
123
+ idpHint="oidc"
124
+ >
125
+ <Dashboard />
126
+ </ProtectedRoute>
127
+ );
128
+ }
129
+ ```
130
+
131
+ ### Utiliser le token pour les appels API
132
+
133
+ ```tsx
134
+ import { useAuth } from '@shane_donnelly/dsi-internal-react-utils';
135
+
136
+ function useAuthFetch() {
137
+ const { token } = useAuth();
138
+
139
+ return (url: string, options?: RequestInit) =>
140
+ fetch(url, {
141
+ ...options,
142
+ headers: {
143
+ ...options?.headers,
144
+ Authorization: `Bearer ${token}`,
145
+ },
146
+ });
147
+ }
148
+ ```
149
+
150
+ ### Accéder à l'instance keycloak-js (usage avancé)
151
+
152
+ ```tsx
153
+ import { useAuth } from '@shane_donnelly/dsi-internal-react-utils';
154
+
155
+ function AdvancedComponent() {
156
+ const { keycloak } = useAuth();
157
+
158
+ // Accès direct à l'instance keycloak-js pour des cas spécifiques
159
+ console.log(keycloak?.tokenParsed);
160
+ }
161
+ ```
@@ -0,0 +1,55 @@
1
+ import { KeycloakProvider as e } from "./keycloak/react/KeycloakProvider/index.js";
2
+ import { useAuth as t } from "./keycloak/react/hooks/useAuth.js";
3
+ import { useEffect as n, useRef as r } from "react";
4
+ import { Fragment as i, jsx as a, jsxs as o } from "react/jsx-runtime";
5
+ import './assets/ProtectedRoute.css';var s = {
6
+ loadingContainer: "_loadingContainer_1th3z_1",
7
+ spinner: "_spinner_1th3z_11",
8
+ spin: "_spin_1th3z_11",
9
+ errorContainer: "_errorContainer_1th3z_26",
10
+ errorMessage: "_errorMessage_1th3z_36"
11
+ };
12
+ //#endregion
13
+ //#region lib/keycloak/react/ProtectedRoute/index.tsx
14
+ function c() {
15
+ return /* @__PURE__ */ o("div", {
16
+ className: s.loadingContainer,
17
+ children: [/* @__PURE__ */ a("div", { className: s.spinner }), /* @__PURE__ */ a("p", { children: "Authentication in progress..." })]
18
+ });
19
+ }
20
+ function l() {
21
+ return /* @__PURE__ */ a("div", {
22
+ className: s.errorContainer,
23
+ children: /* @__PURE__ */ a("p", {
24
+ className: s.errorMessage,
25
+ children: "Authentication error. Please try again later."
26
+ })
27
+ });
28
+ }
29
+ function u({ children: e, fallback: o, errorFallback: s }) {
30
+ let { status: u, login: d } = t(), f = r(!1);
31
+ return n(() => {
32
+ u === "unauthenticated" && !f.current && (f.current = !0, d().catch((e) => {
33
+ console.error("[dsi-keycloak] Login redirect failed:", e);
34
+ }));
35
+ }, [u, d]), u === "loading" || u === "unauthenticated" ? /* @__PURE__ */ a(i, { children: o ?? /* @__PURE__ */ a(c, {}) }) : u === "error" ? /* @__PURE__ */ a(i, { children: s ?? /* @__PURE__ */ a(l, {}) }) : /* @__PURE__ */ a(i, { children: e });
36
+ }
37
+ function d(e) {
38
+ return "config" in e && e.config != null;
39
+ }
40
+ function f(t) {
41
+ if (d(t)) {
42
+ let { config: n, idpHint: r, refreshInterval: i, minTokenValidity: o, onAuthError: s, ...c } = t;
43
+ return /* @__PURE__ */ a(e, {
44
+ config: n,
45
+ idpHint: r,
46
+ refreshInterval: i,
47
+ minTokenValidity: o,
48
+ onAuthError: s,
49
+ children: /* @__PURE__ */ a(u, { ...c })
50
+ });
51
+ }
52
+ return /* @__PURE__ */ a(u, { ...t });
53
+ }
54
+ //#endregion
55
+ export { f as t };
@@ -0,0 +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}
@@ -0,0 +1,22 @@
1
+ import { default as Keycloak } from 'keycloak-js';
2
+ import { KeycloakConfig, AuthUser } from './types';
3
+ /**
4
+ * Crée une nouvelle instance keycloak-js à partir de la configuration.
5
+ * @param config - Configuration du serveur Keycloak
6
+ * @returns Instance Keycloak
7
+ */
8
+ export declare function createKeycloakInstance(config: KeycloakConfig): Keycloak;
9
+ /**
10
+ * Initialise une instance Keycloak avec `check-sso` et PKCE S256.
11
+ * Détecte automatiquement une session SSO existante sans forcer le login.
12
+ *
13
+ * @param keycloak - Instance Keycloak à initialiser
14
+ * @returns `true` si l'utilisateur est déjà authentifié
15
+ */
16
+ export declare function initKeycloak(keycloak: Keycloak): Promise<boolean>;
17
+ /**
18
+ * Extrait les informations utilisateur du token parsé Keycloak.
19
+ * @param keycloak - Instance Keycloak
20
+ * @returns Informations utilisateur ou `null`
21
+ */
22
+ export declare function parseUser(keycloak: Keycloak): AuthUser | null;
@@ -0,0 +1,25 @@
1
+ import e from "keycloak-js";
2
+ //#region lib/keycloak/core/client.ts
3
+ function t(t) {
4
+ return new e({
5
+ url: t.url,
6
+ realm: t.realm,
7
+ clientId: t.clientId
8
+ });
9
+ }
10
+ async function n(e) {
11
+ try {
12
+ return await e.init({
13
+ onLoad: "check-sso",
14
+ pkceMethod: "S256",
15
+ checkLoginIframe: !1
16
+ });
17
+ } catch (e) {
18
+ return console.error("[dsi-keycloak] Init failed:", e), !1;
19
+ }
20
+ }
21
+ function r(e) {
22
+ return e.tokenParsed ? e.tokenParsed : null;
23
+ }
24
+ //#endregion
25
+ export { t as createKeycloakInstance, n as initKeycloak, r as parseUser };
@@ -0,0 +1,67 @@
1
+ import { default as Keycloak } from 'keycloak-js';
2
+ /**
3
+ * Configuration du serveur Keycloak.
4
+ */
5
+ export type KeycloakConfig = {
6
+ /** URL du serveur Keycloak (ex: "https://keycloak.example.com") */
7
+ url: string;
8
+ /** Nom du realm Keycloak */
9
+ realm: string;
10
+ /** Client ID de l'application */
11
+ clientId: string;
12
+ };
13
+ /**
14
+ * Options d'authentification pour le module Keycloak.
15
+ */
16
+ export type KeycloakAuthOptions = {
17
+ /** Hint d'identity provider pour redirection directe (ex: "oidc", "microsoft", "google") */
18
+ idpHint?: string;
19
+ /** Intervalle de rafraîchissement du token en secondes (défaut: 300 = 5min) */
20
+ refreshInterval?: number;
21
+ /** Validité minimale du token en secondes avant rafraîchissement (défaut: 30) */
22
+ minTokenValidity?: number;
23
+ /** Comportement en cas d'erreur d'auth: 'login' pour rediriger, 'logout' pour déconnecter, ou un handler custom */
24
+ onAuthError?: 'login' | 'logout' | ((error: unknown) => void);
25
+ };
26
+ /**
27
+ * État de l'authentification.
28
+ * - `loading` : vérification en cours
29
+ * - `authenticated` : utilisateur connecté
30
+ * - `unauthenticated` : utilisateur non connecté
31
+ * - `error` : erreur lors de l'initialisation
32
+ */
33
+ export type AuthStatus = 'loading' | 'authenticated' | 'unauthenticated' | 'error';
34
+ /**
35
+ * Informations utilisateur extraites du token Keycloak.
36
+ * Contient les claims standard OpenID Connect + toute claim custom.
37
+ */
38
+ export type AuthUser = {
39
+ sub?: string;
40
+ name?: string;
41
+ email?: string;
42
+ preferred_username?: string;
43
+ given_name?: string;
44
+ family_name?: string;
45
+ [key: string]: unknown;
46
+ };
47
+ /**
48
+ * Valeur du contexte d'authentification exposée par `KeycloakProvider` et `useAuth`.
49
+ */
50
+ export type AuthContextValue = {
51
+ /** État actuel de l'authentification */
52
+ status: AuthStatus;
53
+ /** Token d'accès brut (null si non authentifié) */
54
+ token: string | null;
55
+ /** Informations utilisateur extraites du token */
56
+ user: AuthUser | null;
57
+ /** Raccourci pour `status === 'authenticated'` */
58
+ isAuthenticated: boolean;
59
+ /** Instance keycloak-js sous-jacente (pour usage avancé) */
60
+ keycloak: Keycloak | null;
61
+ /** Déclencher une redirection de login. Accepte un idpHint optionnel pour override celui du Provider. */
62
+ login: (idpHint?: string) => Promise<void>;
63
+ /** Déclencher un logout. Accepte un redirectUri optionnel (défaut: origin). */
64
+ logout: (redirectUri?: string) => Promise<void>;
65
+ /** Rafraîchir manuellement le token. Retourne true si réussi. */
66
+ refreshToken: () => Promise<boolean>;
67
+ };
File without changes
@@ -0,0 +1,6 @@
1
+ export { KeycloakProvider } from './react/KeycloakProvider';
2
+ export type { KeycloakProviderProps } from './react/KeycloakProvider';
3
+ export { ProtectedRoute } from './react/ProtectedRoute';
4
+ export type { ProtectedRouteProps } from './react/ProtectedRoute';
5
+ export { useAuth } from './react/hooks/useAuth';
6
+ export type { KeycloakConfig, KeycloakAuthOptions, AuthStatus, AuthUser, AuthContextValue, } from './core/types';
@@ -0,0 +1,4 @@
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 };
@@ -0,0 +1,37 @@
1
+ import { ReactNode } from 'react';
2
+ import { AuthContextValue, KeycloakConfig, KeycloakAuthOptions } from '../../core/types';
3
+ /**
4
+ * Contexte React pour l'authentification Keycloak.
5
+ * Utilisé en interne par `useAuth` et `ProtectedRoute`.
6
+ */
7
+ export declare const KeycloakAuthContext: import('react').Context<AuthContextValue | null>;
8
+ /**
9
+ * Props du composant `KeycloakProvider`.
10
+ */
11
+ export interface KeycloakProviderProps extends KeycloakAuthOptions {
12
+ /** Configuration du serveur Keycloak */
13
+ config: KeycloakConfig;
14
+ /** Contenu de l'application */
15
+ children: ReactNode;
16
+ }
17
+ /**
18
+ * Provider d'authentification Keycloak.
19
+ *
20
+ * Initialise la connexion Keycloak, gère le cycle de vie des tokens
21
+ * (rafraîchissement automatique par intervalle et au retour de l'onglet),
22
+ * et expose l'état d'authentification via le contexte React.
23
+ *
24
+ * Basé sur `keycloak-js`. Utilise `check-sso` avec PKCE S256.
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * <KeycloakProvider
29
+ * config={{ url: 'https://keycloak.example.com', realm: 'my-realm', clientId: 'my-client' }}
30
+ * idpHint="oidc"
31
+ * refreshInterval={300}
32
+ * >
33
+ * <App />
34
+ * </KeycloakProvider>
35
+ * ```
36
+ */
37
+ export declare function KeycloakProvider({ config, children, idpHint, refreshInterval, minTokenValidity, onAuthError, }: KeycloakProviderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,70 @@
1
+ import { createKeycloakInstance as e, initKeycloak as t, parseUser as n } from "../../core/client.js";
2
+ import { createContext as r, useCallback as i, useEffect as a, useRef as o, useState as s } from "react";
3
+ import { jsx as c } from "react/jsx-runtime";
4
+ //#region lib/keycloak/react/KeycloakProvider/index.tsx
5
+ var l = r(null);
6
+ function u({ config: r, children: u, idpHint: d, refreshInterval: f = 300, minTokenValidity: p = 30, onAuthError: m }) {
7
+ let [h, g] = s("loading"), [_, v] = s(null), [y, b] = s(null), x = o(null), S = o(!1), C = i((e) => {
8
+ e.authenticated && e.token ? (v(e.token), b(n(e)), g("authenticated")) : (v(null), b(null), g("unauthenticated"));
9
+ }, []), w = i(async (e) => {
10
+ m === "login" ? await x.current?.login({ idpHint: d }) : m === "logout" ? await x.current?.logout({ redirectUri: window.location.origin }) : typeof m == "function" && m(e);
11
+ }, [m, d]), T = i(async () => {
12
+ let e = x.current;
13
+ if (!e) return !1;
14
+ try {
15
+ return await e.updateToken(p) && C(e), !0;
16
+ } catch (e) {
17
+ return console.warn("[dsi-keycloak] Token refresh failed:", e), await w(e), !1;
18
+ }
19
+ }, [
20
+ p,
21
+ C,
22
+ w
23
+ ]);
24
+ a(() => {
25
+ if (S.current) return;
26
+ S.current = !0;
27
+ let n = e(r);
28
+ x.current = n, t(n).then((e) => {
29
+ C(n), e || g("unauthenticated");
30
+ }).catch((e) => {
31
+ console.error("[dsi-keycloak] Init error:", e), g("error");
32
+ });
33
+ }, []), a(() => {
34
+ if (h !== "authenticated") return;
35
+ let e = window.setInterval(() => {
36
+ T();
37
+ }, f * 1e3), t = () => {
38
+ document.visibilityState === "visible" && T();
39
+ };
40
+ return document.addEventListener("visibilitychange", t), () => {
41
+ clearInterval(e), document.removeEventListener("visibilitychange", t);
42
+ };
43
+ }, [
44
+ h,
45
+ f,
46
+ T
47
+ ]);
48
+ let E = i(async (e) => {
49
+ let t = x.current;
50
+ t && await t.login({ idpHint: e ?? d });
51
+ }, [d]), D = i(async (e) => {
52
+ let t = x.current;
53
+ t && await t.logout({ redirectUri: e ?? window.location.origin });
54
+ }, []), O = {
55
+ status: h,
56
+ token: _,
57
+ user: y,
58
+ isAuthenticated: h === "authenticated",
59
+ keycloak: x.current,
60
+ login: E,
61
+ logout: D,
62
+ refreshToken: T
63
+ };
64
+ return /* @__PURE__ */ c(l.Provider, {
65
+ value: O,
66
+ children: u
67
+ });
68
+ }
69
+ //#endregion
70
+ export { l as KeycloakAuthContext, u as KeycloakProvider };
@@ -0,0 +1,69 @@
1
+ import { ReactNode } from 'react';
2
+ import { KeycloakConfig, KeycloakAuthOptions } from '../../core/types';
3
+ /**
4
+ * Props de base du composant `ProtectedRoute`.
5
+ */
6
+ interface BaseProtectedRouteProps {
7
+ /** Contenu protégé, affiché une fois authentifié */
8
+ children: ReactNode;
9
+ /** Composant affiché pendant le chargement / la redirection (défaut: spinner) */
10
+ fallback?: ReactNode;
11
+ /** Composant affiché en cas d'erreur d'authentification (défaut: message d'erreur) */
12
+ errorFallback?: ReactNode;
13
+ }
14
+ /**
15
+ * Props pour le mode standalone (sans `KeycloakProvider` parent).
16
+ * Inclut la configuration Keycloak et les options d'authentification.
17
+ */
18
+ interface StandaloneProtectedRouteProps extends BaseProtectedRouteProps, KeycloakAuthOptions {
19
+ /** Configuration du serveur Keycloak */
20
+ config: KeycloakConfig;
21
+ }
22
+ /**
23
+ * Props pour le mode contexte (à l'intérieur d'un `KeycloakProvider`).
24
+ */
25
+ type ContextProtectedRouteProps = BaseProtectedRouteProps;
26
+ /**
27
+ * Union des props acceptées par `ProtectedRoute`.
28
+ */
29
+ export type ProtectedRouteProps = StandaloneProtectedRouteProps | ContextProtectedRouteProps;
30
+ /**
31
+ * Composant de protection de route / zone authentifiée.
32
+ *
33
+ * Fonctionne en deux modes :
34
+ *
35
+ * **Mode standalone** (plug & play) : fournir `config` et les options directement.
36
+ * Crée automatiquement un `KeycloakProvider` interne.
37
+ *
38
+ * **Mode contexte** : utiliser à l'intérieur d'un `KeycloakProvider` parent.
39
+ * Ne nécessite que `children` et optionnellement `fallback` / `errorFallback`.
40
+ *
41
+ * Dans les deux cas, le composant :
42
+ * - Vérifie l'état d'authentification via `check-sso`
43
+ * - Redirige vers le login Keycloak (via l'IDP configuré) si non authentifié
44
+ * - Affiche un fallback pendant le chargement
45
+ * - Rend les enfants une fois authentifié
46
+ *
47
+ * Basé sur `keycloak-js`.
48
+ *
49
+ * @example Mode standalone (plug & play)
50
+ * ```tsx
51
+ * <ProtectedRoute
52
+ * config={{ url: 'https://keycloak.example.com', realm: 'my-realm', clientId: 'my-client' }}
53
+ * idpHint="oidc"
54
+ * >
55
+ * <Dashboard />
56
+ * </ProtectedRoute>
57
+ * ```
58
+ *
59
+ * @example Mode contexte (avec KeycloakProvider parent)
60
+ * ```tsx
61
+ * <KeycloakProvider config={...} idpHint="oidc">
62
+ * <ProtectedRoute>
63
+ * <Dashboard />
64
+ * </ProtectedRoute>
65
+ * </KeycloakProvider>
66
+ * ```
67
+ */
68
+ export declare function ProtectedRoute(props: ProtectedRouteProps): import("react/jsx-runtime").JSX.Element;
69
+ export {};
@@ -0,0 +1,2 @@
1
+ import { t as e } from "../../../ProtectedRoute-Bl0cCdQ2.js";
2
+ export { e as ProtectedRoute };
@@ -0,0 +1,39 @@
1
+ import { AuthContextValue } from '../../core/types';
2
+ /**
3
+ * Hook d'authentification Keycloak.
4
+ *
5
+ * Donne accès à l'état d'authentification, au token, aux infos utilisateur,
6
+ * et aux actions (login, logout, refreshToken).
7
+ *
8
+ * Doit être utilisé à l'intérieur d'un `KeycloakProvider` ou d'un `ProtectedRoute` avec `config`.
9
+ *
10
+ * @returns Objet d'authentification complet
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function UserProfile() {
15
+ * const { user, token, isAuthenticated, logout } = useAuth();
16
+ *
17
+ * if (!isAuthenticated) return null;
18
+ *
19
+ * return (
20
+ * <div>
21
+ * <p>Bonjour {user?.name}</p>
22
+ * <button onClick={() => logout()}>Déconnexion</button>
23
+ * </div>
24
+ * );
25
+ * }
26
+ * ```
27
+ *
28
+ * @example Utiliser le token pour des appels API
29
+ * ```tsx
30
+ * function useFetchWithAuth(url: string) {
31
+ * const { token } = useAuth();
32
+ *
33
+ * return fetch(url, {
34
+ * headers: { Authorization: `Bearer ${token}` },
35
+ * });
36
+ * }
37
+ * ```
38
+ */
39
+ export declare function useAuth(): AuthContextValue;
@@ -0,0 +1,10 @@
1
+ import { KeycloakAuthContext as e } from "../KeycloakProvider/index.js";
2
+ import { useContext as t } from "react";
3
+ //#region lib/keycloak/react/hooks/useAuth.ts
4
+ function n() {
5
+ let n = t(e);
6
+ if (!n) throw Error("[dsi-keycloak] useAuth() must be used within a <KeycloakProvider> or a <ProtectedRoute config={...}>.");
7
+ return n;
8
+ }
9
+ //#endregion
10
+ export { n as useAuth };
package/dist/main.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export { KeycloakProvider, ProtectedRoute, useAuth, } from './keycloak';
2
+ export type { KeycloakProviderProps, ProtectedRouteProps, KeycloakConfig, KeycloakAuthOptions, AuthStatus, AuthUser, AuthContextValue, } from './keycloak';
package/dist/main.js CHANGED
@@ -1,2 +1,5 @@
1
- import { t as e } from "./Example-CYi9vFcY.js";
2
- export { e as Example };
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";
4
+ import "./keycloak/index.js";
5
+ export { e as KeycloakProvider, n as ProtectedRoute, t as useAuth };
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.0.1",
4
+ "version": "0.1.0",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
@@ -28,7 +28,8 @@
28
28
  "vite-plugin-dts": "^4.5.4",
29
29
  "vite-plugin-lib-inject-css": "^2.2.2",
30
30
  "react": "^19.2.4",
31
- "react-dom": "^19.2.4"
31
+ "react-dom": "^19.2.4",
32
+ "keycloak-js": "^26.0.0"
32
33
  },
33
34
  "main": "dist/main.js",
34
35
  "types": "dist/main.d.ts",
@@ -40,6 +41,7 @@
40
41
  ],
41
42
  "peerDependencies": {
42
43
  "react": "^19.2.4",
43
- "react-dom": "^19.2.4"
44
+ "react-dom": "^19.2.4",
45
+ "keycloak-js": ">=25.0.0"
44
46
  }
45
47
  }
@@ -1,12 +0,0 @@
1
- import { jsx as e } from "react/jsx-runtime";
2
- import './assets/Example.css';var t = { text: "_text_acpj5_1" };
3
- //#endregion
4
- //#region lib/components/Example/index.tsx
5
- function n() {
6
- return /* @__PURE__ */ e("p", {
7
- className: t.text,
8
- children: "Example"
9
- });
10
- }
11
- //#endregion
12
- export { n as t };
@@ -1 +0,0 @@
1
- ._text_acpj5_1{color:red}
@@ -1,2 +0,0 @@
1
- import { t as e } from "../../Example-CYi9vFcY.js";
2
- export { e as Example };