@ollaid/native-sso 2.1.5 → 2.5.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
@@ -28,6 +28,7 @@ Package NPM Frontend-First pour l'authentification Native SSO Ollaid.
28
28
  19. [Sécurité](#sécurité)
29
29
  20. [Exports](#exports)
30
30
  21. [Publication & Installation npm](#publication--installation-npm)
31
+ 22. [Webhooks & Health Check (Backend)](#webhooks--health-check-backend)
31
32
 
32
33
  ---
33
34
 
@@ -59,7 +60,7 @@ function App() {
59
60
  return (
60
61
  <Routes>
61
62
  <Route
62
- path="/auth/sso"
63
+ path="/auth/native-sso"
63
64
  element={
64
65
  <NativeSSOPage
65
66
  saasApiUrl="https://mon-saas.com/api"
@@ -69,7 +70,7 @@ function App() {
69
70
  console.log('Connecté !', user.name);
70
71
  navigate('/dashboard');
71
72
  }}
72
- onLogout={() => navigate('/auth/sso')}
73
+ onLogout={() => navigate('/auth/native-sso')}
73
74
  />
74
75
  }
75
76
  />
@@ -81,7 +82,7 @@ function App() {
81
82
 
82
83
  ### 3. C'est tout ✅
83
84
 
84
- La page `/auth/sso` gère automatiquement :
85
+ La page `/auth/native-sso` gère automatiquement :
85
86
  - ✅ Connexion par email (mot de passe + OTP)
86
87
  - ✅ Connexion par téléphone (SMS OTP)
87
88
  - ✅ Connexion par code d'accès
@@ -104,15 +105,16 @@ La page `/auth/sso` gère automatiquement :
104
105
  | `configPrefix` | `string` | ❌ | **Multi-tenant** : préfixe de configuration IAM côté backend (défaut: `'iam'`). Permet à un même backend SaaS de gérer N applications IAM. Voir [Multi-Tenant](#multi-tenant-plusieurs-applications-sur-le-même-backend). |
105
106
  | `onLoginSuccess` | `(token: string, user: UserInfos) => void` | ❌ | Callback après connexion réussie |
106
107
  | `onLogout` | `() => void` | ❌ | Callback après déconnexion |
107
- | `title` | `string` | ❌ | Titre personnalisé (défaut: "Un compte, plusieurs accès") |
108
+ | `title` | `string` | ❌ | Titre personnalisé (défaut: "Un compte pour toutes vos applications") |
108
109
  | `description` | `string` | ❌ | Description personnalisée |
109
110
  | `logoUrl` | `string` | ❌ | URL du logo (remplace le slider) |
110
111
  | `hideFooter` | `boolean` | ❌ | Masquer "Propulsé par iam.ollaid.com" |
111
- | `onOnboardingComplete` | `(data: { image_url?: string; ccphone?: string; phone?: string }) => void` | ❌ | Callback après complétion de l'onboarding |
112
+ | `onOnboardingComplete` | `(data: { name?: string; image_url?: string; ccphone?: string; phone?: string; email?: string }) => void` | ❌ | Callback après complétion de l'onboarding |
112
113
  | `redirectAfterLogin` | `string` | ❌ | Route vers laquelle rediriger après connexion réussie (ex: `/client/dashboard`). Utilise `window.location.href`. Compatible avec ou sans react-router. |
113
114
  | `redirectAfterLogout` | `string` | ❌ | Route vers laquelle rediriger après déconnexion (ex: `/auth/client`). Utilise `window.location.href`. |
114
115
 
115
116
  > **Note :** Le mode `debug` est contrôlé **uniquement** par le backend via la variable d'environnement `IAM_DEBUG` dans le `.env` du SaaS. Il n'y a plus de prop `debug` à passer au composant. Le `DebugPanel` est **réactif** : il apparaît automatiquement après le chargement des credentials si `debug: true` est retourné par le backend.
117
+ > Quand le `DebugPanel` est visible, il expose aussi des boutons de test pour ouvrir `Connexion`, `Inscription`, `Infos profile` et un reset du rappel profil.
116
118
 
117
119
  ### Redirections automatiques (optionnel)
118
120
 
@@ -175,7 +177,7 @@ const handleLogout = async () => {
175
177
 
176
178
  1. **Révoque le token SaaS** — `POST /api/native/logout` (supprime le Sanctum token)
177
179
  2. **Révoque la session IAM** — `POST /api/iam/disconnect` (avec `sanctum_token` + `app_access_token_ref`)
178
- 3. **Nettoie le localStorage** — supprime les 6 clés du package
180
+ 3. **Nettoie le localStorage** — supprime les clés de session du package
179
181
 
180
182
  Les appels réseau sont en `Promise.allSettled` (best-effort) : même si le serveur est injoignable, le localStorage est **toujours** nettoyé.
181
183
 
@@ -189,6 +191,9 @@ Les appels réseau sont en `Promise.allSettled` (best-effort) : même si le serv
189
191
  | `account_type` | Type de compte (`user` ou `client`) |
190
192
  | `alias_reference` | Référence de l'alias de connexion |
191
193
  | `app_access_token_ref` | Référence de l'`AppAccessToken` IAM (pour revocation optimisée) |
194
+ | `refresh_token` | Refresh token SaaS (si activé) |
195
+ | `token_expires_at` | Expiration du token Sanctum (si fournie) |
196
+ | `refresh_expires_at` | Expiration du refresh token (si fournie) |
192
197
 
193
198
  ### ⛔ `clearAuthToken()` est déprécié
194
199
 
@@ -235,7 +240,7 @@ Backend SaaS:
235
240
  configPrefix="iam"
236
241
  accountType="user"
237
242
  redirectAfterLogin="/dashboard"
238
- redirectAfterLogout="/auth/sso"
243
+ redirectAfterLogout="/auth/native-sso"
239
244
  />
240
245
 
241
246
  {/* Page login espace vendeur */}
@@ -329,7 +334,7 @@ return [
329
334
 
330
335
  ### Côté Backend SaaS — Controller multi-tenant
331
336
 
332
- Tous les controllers Native (`config`, `exchange`, `check-token`, `logout`) doivent lire le header :
337
+ Tous les controllers Native (`config`, `exchange`, `check-token`, `refresh`, `logout`) doivent lire le header :
333
338
 
334
339
  ```php
335
340
  class NativeConfigController extends Controller
@@ -374,7 +379,11 @@ class NativeConfigController extends Controller
374
379
  }
375
380
  ```
376
381
 
377
- > **⚠️ Important** : Appliquez la même logique `X-IAM-Config-Prefix` dans `exchange`, `check-token` et `logout`.
382
+ > **⚠️ Important** : Appliquez la même logique `X-IAM-Config-Prefix` dans `exchange`, `check-token`, `refresh` et `logout`.
383
+
384
+ Le package envoie aussi :
385
+ - `X-Device-Id` (stable par appareil / webview)
386
+ - `X-Session-UUID` (UUID stable par instance, pour différencier plusieurs sessions sur un même device)
378
387
 
379
388
  ---
380
389
 
@@ -618,7 +627,8 @@ import { useMobileRegistration } from '@ollaid/native-sso';
618
627
 
619
628
  ## Backend SaaS — Endpoints requis
620
629
 
621
- Le backend SaaS (Laravel) doit exposer **4 endpoints**. Voici les spécifications exactes :
630
+ Le backend SaaS (Laravel) doit exposer **5 endpoints** : `config`, `exchange`, `check-token`, `refresh`, `logout`.
631
+ Voici les spécifications exactes :
622
632
 
623
633
  ### `GET /api/native/config`
624
634
 
@@ -826,6 +836,7 @@ Vérifie la validité du token Sanctum et retourne les infos utilisateur fraîch
826
836
  **Réponse succès (200) :**
827
837
  ```json
828
838
  {
839
+ "success": true,
829
840
  "status": "connected",
830
841
  "user": {
831
842
  "name": "John Doe",
@@ -849,6 +860,7 @@ Route::post('/native/check-token', function (Request $request) {
849
860
  $user = $request->user();
850
861
 
851
862
  return response()->json([
863
+ 'success' => true,
852
864
  'status' => 'connected',
853
865
  'user' => [
854
866
  'name' => $user->name,
@@ -864,7 +876,46 @@ Route::post('/native/check-token', function (Request $request) {
864
876
  })->middleware('auth:sanctum');
865
877
  ```
866
878
 
867
- > **Comportement réseau :** Le package ne déconnecte l'utilisateur que si le backend retourne explicitement **401**. En cas d'erreur réseau, timeout ou serveur inaccessible, la session est conservée.
879
+ > **Règle de déconnexion :** Le package ne déconnecte l'utilisateur **que** sur un **HTTP 401 explicite**. Tout HTTP 200 (quelle que soit la structure du body) confirme la session. Erreur réseau, timeout, 5xx, offline → session conservée, jamais de déconnexion inutile.
880
+
881
+ ---
882
+
883
+ ### `POST /api/native/refresh` (OBLIGATOIRE pour la stabilité)
884
+
885
+ Renouvelle la session **sans déconnecter**. Le package l'utilise :
886
+ - en **proactif** (avant expiration, si `expires_at` est fourni)
887
+ - en **récupération** quand `check-token` retourne `401` (tente un refresh avant logout)
888
+
889
+ **Body :**
890
+ ```json
891
+ { "refresh_token": "rt_..." }
892
+ ```
893
+
894
+ **Recommandation (stabilité maximale) :** ne pas changer le token Sanctum.
895
+ Le refresh doit **prolonger `expires_at`** du token existant (le client garde son token actuel).
896
+
897
+ **Réponse succès (200) :**
898
+ ```json
899
+ {
900
+ "success": true,
901
+ "expires_at": "2026-06-13T12:00:00+00:00",
902
+ "refresh_token": "rt_new_...",
903
+ "refresh_expires_at": "2026-08-13T12:00:00+00:00",
904
+ "user": { "name": "John Doe" }
905
+ }
906
+ ```
907
+
908
+ **Réponse refresh invalide (401) :**
909
+ ```json
910
+ {
911
+ "success": false,
912
+ "error_type": "invalid_refresh",
913
+ "message": "Refresh token invalide ou expiré"
914
+ }
915
+ ```
916
+
917
+ > Si le refresh est invalide (`401 invalid_refresh`) : c'est une révocation explicite, la déconnexion est autorisée.
918
+ > Si offline/timeout/5xx : ne jamais déconnecter.
868
919
 
869
920
  ---
870
921
 
@@ -900,7 +951,7 @@ Route::post('/native/logout', function (Request $request) {
900
951
 
901
952
  ## Controller Laravel Complet (copier-coller)
902
953
 
903
- Voici un `NativeAuthController.php` complet regroupant les 4 endpoints. Copiez-le dans `app/Http/Controllers/Api/NativeAuthController.php` :
954
+ Voici un `NativeAuthController.php` complet regroupant les 5 endpoints. Copiez-le dans `app/Http/Controllers/Api/NativeAuthController.php` :
904
955
 
905
956
  ```php
906
957
  <?php
@@ -1122,6 +1173,7 @@ class NativeAuthController extends Controller
1122
1173
  $user = $request->user();
1123
1174
 
1124
1175
  return response()->json([
1176
+ 'success' => true,
1125
1177
  'status' => 'connected',
1126
1178
  'message' => 'Utilisateur connecté',
1127
1179
  'user' => [
@@ -1340,6 +1392,14 @@ public function up(): void
1340
1392
 
1341
1393
  > **Note :** Le champ `reference` est l'identifiant unique IAM de l'utilisateur. Le champ `alias_reference` identifie l'utilisateur dans le contexte d'une application spécifique.
1342
1394
 
1395
+ ### Colonnes recommandées sur `personal_access_tokens` (Sanctum)
1396
+
1397
+ Pour la révocation synchronisée et la stabilité de session :
1398
+ - `app_access_token_ref` (révocation IAM ciblée)
1399
+ - `refresh_token_hash` + `refresh_expires_at` (refresh token)
1400
+
1401
+ Ces migrations sont détaillées dans `BACKEND_INTEGRATION.md` du package.
1402
+
1343
1403
  ---
1344
1404
 
1345
1405
  ## Flux d'authentification
@@ -1384,7 +1444,7 @@ public function up(): void
1384
1444
  4. **Validate** — Le frontend envoie le mot de passe/OTP, l'IAM retourne un `callback_token`
1385
1445
  5. **Exchange** — Le frontend envoie le `callback_token` au backend SaaS, qui le décrypte via l'IAM et crée une session Sanctum
1386
1446
 
1387
- > **Important :** Le package gère les étapes 1-5 automatiquement. Le backend SaaS doit implémenter **4 endpoints** (`config`, `exchange`, `check-token`, `logout`).
1447
+ > **Important :** Le package gère les étapes 1-5 automatiquement. Le backend SaaS doit implémenter **5 endpoints** (`config`, `exchange`, `check-token`, `refresh`, `logout`).
1388
1448
 
1389
1449
  ---
1390
1450
 
@@ -1894,7 +1954,7 @@ Toutes les APIs IAM retournent le même objet `user_infos` avec exactement **9 c
1894
1954
 
1895
1955
  ## Session & localStorage
1896
1956
 
1897
- Le package utilise **6 clés** dans `localStorage` pour persister la session :
1957
+ Le package utilise **9 clés** dans `localStorage` pour persister la session et le suivi du profil :
1898
1958
 
1899
1959
  | Clé | Contenu | Source | Valeurs possibles |
1900
1960
  |-----|---------|--------|-------------------|
@@ -1904,8 +1964,12 @@ Le package utilise **6 clés** dans `localStorage` pour persister la session :
1904
1964
  | `account_type` | Type de compte | Déterminé lors du `exchange` selon le mode d'inscription | `"user"` (défaut) ou `"client"` (inscription phone-only) |
1905
1965
  | `alias_reference` | Référence alias utilisée lors de la connexion | Réponse de `/api/native/exchange` (champ `user.alias_reference`) | `"ALI-XXXXXXXX"` |
1906
1966
  | `app_access_token_ref` | Référence de l'`AppAccessToken` IAM | Réponse de `/api/native/exchange` (champ `app_access_token_ref`) | `"42"` ou `"aat_ref_abc123"` |
1967
+ | `sso_image_last_status` | Statut du dernier onboarding profil | Mis à jour par `OnboardingModal` | `"true"` ou `"false"` |
1968
+ | `sso_image_last_check` | Timestamp du dernier contrôle profil | Mis à jour par `OnboardingModal` / sync profil | Millisecondes Unix |
1969
+ | `sso_image_recheck_at` | Timestamp de rappel après snooze | Mis à jour quand l'utilisateur passe l'onboarding | Millisecondes Unix |
1907
1970
 
1908
1971
  > **Note :** `account_type` et `alias_reference` sont stockés **séparément** de l'objet `user` en plus d'être inclus dans le JSON de la clé `user`.
1972
+ > **Note :** `sso_image_last_status`, `sso_image_last_check` et `sso_image_recheck_at` vivent dans le `localStorage` du SaaS et servent au rappel d'onboarding du profil.
1909
1973
 
1910
1974
  #### Champs enrichis dans l'objet `user`
1911
1975
 
@@ -1915,7 +1979,8 @@ L'objet `user` stocké en localStorage contient deux champs ajoutés automatique
1915
1979
 
1916
1980
  ### Nettoyage
1917
1981
 
1918
- Lors du `logout()`, les 6 clés sont supprimées via `clearAuthToken()`.
1982
+ Lors du `logout()`, les 6 clés de session sont supprimées via `clearAuthToken()`.
1983
+ Les clés de rappel profil (`sso_image_*`) ne sont pas effacées, afin de conserver le comportement de relance après snooze.
1919
1984
 
1920
1985
  ### Accès programmatique
1921
1986
 
@@ -2052,7 +2117,7 @@ Le [health check](#usetokenhealthcheck) (toutes les 2 min) détecte automatiquem
2052
2117
 
2053
2118
  ---
2054
2119
 
2055
- Modal post-connexion qui invite l'utilisateur à compléter les informations manquantes de son profil.
2120
+ Modal post-connexion qui invite l'utilisateur à compléter les informations manquantes de son profil, ou à éditer ses informations complètes depuis un SaaS.
2056
2121
 
2057
2122
  ### Props
2058
2123
 
@@ -2061,35 +2126,102 @@ Modal post-connexion qui invite l'utilisateur à compléter les informations man
2061
2126
  | `open` | `boolean` | ✅ | Contrôle l'ouverture de la modal |
2062
2127
  | `onOpenChange` | `(open: boolean) => void` | ✅ | Callback changement d'état |
2063
2128
  | `user` | `NativeUser` | ✅ | Objet utilisateur courant (pour détecter les champs manquants) |
2129
+ | `variant` | `'missing' \| 'edit'` | ❌ | `missing` affiche uniquement les champs absents, `edit` affiche les champs de base en mode édition complet |
2064
2130
  | `onComplete` | `(data) => void` | ✅ | Callback avec les données saisies |
2065
2131
  | `onSkip` | `() => void` | ✅ | Callback si l'utilisateur passe l'étape |
2066
2132
 
2067
2133
  ### Champs affichés
2068
2134
 
2069
- La modal affiche **uniquement** les champs manquants :
2070
- - **Photo de profil** — si `user.image_url` est vide (max 2 Mo, JPG/PNG)
2071
- - **Numéro de téléphone** si `user.phone` est vide
2072
- - **Adresse email** — si `user.email` est vide (**optionnel**, ne bloque pas la validation)
2135
+ La modal gère **deux modes** :
2136
+
2137
+ - **Mode `missing`** : affiche uniquement les champs manquants
2138
+ - **Nom complet** — si `user.name` est vide
2139
+ - **Photo de profil** — si `user.image_url` est vide (max 2 Mo, JPG/PNG)
2140
+ - **Numéro de téléphone** — si `user.phone` est vide
2141
+ - **Adresse email** — si `user.email` est vide
2142
+ - **Mode `edit`** : affiche les champs de base éditables même si le profil est déjà complet
2143
+ - Nom complet
2144
+ - Photo de profil
2145
+ - Numéro de téléphone en lecture seule avec bouton `Changer téléphone`
2146
+ - Adresse email en lecture seule avec bouton `Changer email`
2073
2147
 
2074
2148
  ### Callback `onComplete`
2075
2149
 
2076
2150
  ```ts
2077
2151
  onComplete: (data: {
2152
+ name?: string; // Nom complet (si fourni ou modifié)
2078
2153
  image_url?: string; // Base64 de la photo (si ajoutée)
2079
2154
  ccphone?: string; // Indicatif (si téléphone ajouté)
2080
2155
  phone?: string; // Numéro (si téléphone ajouté)
2081
- email?: string; // Email (si renseigné — optionnel)
2156
+ email?: string; // Email (si renseigné)
2082
2157
  }) => void;
2083
2158
  ```
2084
2159
 
2085
2160
  ### Condition de soumission
2086
2161
 
2087
2162
  L'utilisateur **doit** :
2088
- 1. Cocher la case de confirmation
2089
- 2. Fournir une photo (si manquante)
2090
- 3. Fournir un téléphone valide (si manquant)
2163
+ 1. Fournir un nom si le nom est affiché
2164
+ 2. Fournir une photo si elle est affichée
2165
+ 3. Fournir un téléphone valide si le champ est affiché
2166
+ 4. Fournir un email valide si le champ est affiché
2167
+
2168
+ Après connexion, la page autonome attend 5 minutes avant d'ouvrir cette modal si le profil est incomplet.
2169
+ Si l'utilisateur la ferme sans compléter, le package enregistre un snooze de 8 heures (`sso_image_last_status=false`, `sso_image_last_check=now`, `sso_image_recheck_at=now+8h`).
2170
+ Un sync profil best-effort relit ensuite l'état utilisateur toutes les 30 minutes et remet `sso_image_last_status=true` dès que le profil est complet.
2171
+
2172
+ ### Mode automatique
2173
+
2174
+ Le mode automatique est piloté par `NativeSSOPage` :
2175
+ - la modal s'ouvre après le délai de 5 minutes si des infos sont manquantes,
2176
+ - elle reste sur un écran de chargement tant que l'hydratation IAM n'a pas renvoyé le profil,
2177
+ - elle affiche ensuite uniquement les champs manquants,
2178
+ - si l'utilisateur ferme la modal, le rappel est repoussé de 8 heures.
2091
2179
 
2092
- L'email est **toujours optionnel** il n'est pas requis pour valider.
2180
+ ### Mode manuel depuis un SaaS
2181
+
2182
+ Quand vous ouvrez la modal depuis votre SaaS via un bouton "Infos profil" ou "Modifier mon profil", utilisez `variant="edit"`.
2183
+
2184
+ Exemple :
2185
+
2186
+ ```tsx
2187
+ import { useState } from 'react';
2188
+ import { OnboardingModal } from '@ollaid/native-sso';
2189
+
2190
+ export function ProfileButton({ user }: { user: NativeUser }) {
2191
+ const [open, setOpen] = useState(false);
2192
+
2193
+ return (
2194
+ <>
2195
+ <button type="button" onClick={() => setOpen(true)}>
2196
+ Infos profil
2197
+ </button>
2198
+
2199
+ <OnboardingModal
2200
+ open={open}
2201
+ onOpenChange={setOpen}
2202
+ onDismiss={() => setOpen(false)}
2203
+ user={user}
2204
+ variant="edit"
2205
+ profileHydrating={false}
2206
+ onComplete={(data) => {
2207
+ // Mettre à jour votre cache local / localStorage avec data.user_infos
2208
+ setOpen(false);
2209
+ }}
2210
+ onSkip={() => setOpen(false)}
2211
+ />
2212
+ </>
2213
+ );
2214
+ }
2215
+ ```
2216
+
2217
+ Dans ce mode, le changement de téléphone/email ouvre un sous-flux OTP dans la même modal:
2218
+ 1. saisie du nouveau téléphone/email,
2219
+ 2. envoi du premier OTP sur le contact actuel,
2220
+ 3. vérification du premier OTP,
2221
+ 4. envoi d'un second OTP sur le nouveau contact,
2222
+ 5. confirmation finale et mise à jour du profil.
2223
+
2224
+ Les écrans de changement restent en `static backdrop` côté package: un clic hors modal ne ferme pas le flux.
2093
2225
 
2094
2226
  ### Exemple
2095
2227
 
@@ -2100,6 +2232,7 @@ import { OnboardingModal } from '@ollaid/native-sso';
2100
2232
  open={showOnboarding}
2101
2233
  onOpenChange={setShowOnboarding}
2102
2234
  user={currentUser}
2235
+ variant="edit"
2103
2236
  onComplete={async (data) => {
2104
2237
  // Envoyer les données au backend pour mise à jour
2105
2238
  await api.updateProfile(data);
@@ -2248,6 +2381,9 @@ if (config('services.iam.debug')) {
2248
2381
  - `getAuthToken` — Récupérer le token depuis localStorage
2249
2382
  - `getAuthUser` — Récupérer l'utilisateur depuis localStorage
2250
2383
  - `getAccountType` — Récupérer le type de compte depuis localStorage
2384
+ - `getDeviceId` — Récupérer/générer le `X-Device-Id` (persisté)
2385
+ - `getSessionUuid` — Récupérer/générer le `X-Session-UUID` (persisté)
2386
+ - `STORAGE_KEYS` — Constantes des clés localStorage utilisées par le package
2251
2387
 
2252
2388
  ### Types
2253
2389
  - `UserInfos`, `NativeAuthState`, `NativeAuthStatus`, `NativeCredentials`, etc.
@@ -2352,3 +2488,16 @@ npm publish --access public # 3. Publier sur npm
2352
2488
  ## Licence
2353
2489
 
2354
2490
  Propriétaire — Ollaid © 2026
2491
+
2492
+ ---
2493
+
2494
+ ## Webhooks & Health Check (Backend)
2495
+
2496
+ Pour garantir la fiabilité et la synchronisation en temps réel (ex: révocation instantanée d'une session bannie), votre backend doit implémenter deux briques supplémentaires.
2497
+
2498
+ Consultez le guide détaillé : [**WEBHOOKS_HEALTH.md**](./WEBHOOKS_HEALTH.md)
2499
+
2500
+ | Brique | Rôle |
2501
+ |--------|------|
2502
+ | **Health Check** | Permet à l'IAM de vérifier que votre SaaS est "Healthy" et bien configuré. |
2503
+ | **Webhooks** | Permet à l'IAM de notifier votre SaaS d'événements critiques (suspension, révocation). |
@@ -0,0 +1,16 @@
1
+ /**
2
+ * AvatarCropModal — recadrage carré simple et déterministe
3
+ *
4
+ * Version réécrite from scratch pour éviter les états qui bloquent le bouton Valider.
5
+ *
6
+ * @version 2.5.0
7
+ */
8
+ export interface AvatarCropModalProps {
9
+ open: boolean;
10
+ imageSrc: string | null;
11
+ onOpenChange: (open: boolean) => void;
12
+ onCancel: () => void;
13
+ onConfirm: (blob: Blob) => Promise<void> | void;
14
+ }
15
+ export declare function AvatarCropModal({ open, imageSrc, onOpenChange, onCancel, onConfirm }: AvatarCropModalProps): import("react/jsx-runtime").JSX.Element;
16
+ export default AvatarCropModal;
@@ -2,11 +2,16 @@
2
2
  * DebugPanel — Panneau de debug flottant pour @ollaid/native-sso
3
3
  * Affiche l'historique des appels API en temps réel (style terminal)
4
4
  * N'apparaît que quand debug=true
5
- * @version 2.1.4
5
+ * @version 2.5.0
6
6
  */
7
+ export type DebugOnboardingPreset = 'current' | 'photo' | 'phone' | 'email' | 'all';
7
8
  interface DebugPanelProps {
8
9
  saasApiUrl: string;
9
10
  iamApiUrl: string;
11
+ onOpenLogin?: () => void;
12
+ onOpenSignup?: () => void;
13
+ onOpenOnboarding?: (preset: DebugOnboardingPreset) => void;
14
+ onResetProfilePrompt?: () => void;
10
15
  }
11
- export declare function DebugPanel({ saasApiUrl, iamApiUrl }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onResetProfilePrompt }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
12
17
  export default DebugPanel;
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Login Modal for @ollaid/native-sso
3
- * Complete login flow aligned with web SSO /sso/auth design
3
+ * Complete login flow aligned with Native SSO design
4
4
  *
5
- * @version 2.1.4
5
+ * @version 2.5.0
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  export interface LoginModalProps {
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * NativeSSOPage — Page autonome complète pour @ollaid/native-sso
3
- * Design aligné sur /sso/auth (fond primary, card blanche, ShieldCheck branding)
3
+ * Design aligné sur le parcours Native SSO (fond primary, card blanche, ShieldCheck branding)
4
4
  *
5
- * @version 2.1.4
5
+ * @version 2.5.0
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  export interface NativeSSOPageProps {
@@ -11,9 +11,15 @@ export interface NativeSSOPageProps {
11
11
  onLoginSuccess?: (token: string, user: UserInfos) => void;
12
12
  onLogout?: () => void;
13
13
  onOnboardingComplete?: (data: {
14
+ name?: string;
14
15
  image_url?: string;
15
16
  ccphone?: string;
16
17
  phone?: string;
18
+ email?: string;
19
+ address?: string;
20
+ town?: string;
21
+ country?: string;
22
+ user_infos?: UserInfos;
17
23
  }) => void;
18
24
  accountType?: 'user' | 'client';
19
25
  configPrefix?: string;
@@ -1,23 +1,30 @@
1
1
  /**
2
- * OnboardingModal — Post-login modal for missing profile info
3
- * Asks for photo + phone if not present in user_infos
2
+ * OnboardingModal — Modal de profil unifiée
3
+ * Mode `missing` : champs absents uniquement
4
+ * Mode `edit` : édition complète du profil depuis le SaaS
4
5
  *
5
- * @version 2.1.4
6
+ * @version 2.5.0
6
7
  */
7
- import type { NativeUser } from '../types/native';
8
+ import type { NativeUser, UserInfos } from '../types/native';
8
9
  export interface OnboardingModalProps {
9
10
  open: boolean;
10
11
  onOpenChange: (open: boolean) => void;
12
+ onDismiss: () => void;
11
13
  user: NativeUser;
12
- /** Called with updated data when user submits */
14
+ variant?: 'missing' | 'edit';
15
+ profileHydrating?: boolean;
13
16
  onComplete: (data: {
17
+ name?: string;
14
18
  image_url?: string;
15
19
  ccphone?: string;
16
20
  phone?: string;
17
21
  email?: string;
22
+ address?: string;
23
+ town?: string;
24
+ country?: string;
25
+ user_infos?: UserInfos;
18
26
  }) => void;
19
- /** Called when user skips onboarding */
20
27
  onSkip: () => void;
21
28
  }
22
- export declare function OnboardingModal({ open, onOpenChange, user, onComplete, onSkip }: OnboardingModalProps): import("react/jsx-runtime").JSX.Element;
29
+ export declare function OnboardingModal({ open, onOpenChange, onDismiss, user, variant, profileHydrating, onComplete, onSkip }: OnboardingModalProps): import("react/jsx-runtime").JSX.Element;
23
30
  export default OnboardingModal;
@@ -3,7 +3,7 @@
3
3
  * Flow: email → method-choice → OTP → new password → success
4
4
  * Design aligned with web SSO
5
5
  *
6
- * @version 2.1.4
6
+ * @version 2.5.0
7
7
  */
8
8
  export interface PasswordRecoveryModalProps {
9
9
  open: boolean;
@@ -8,9 +8,10 @@ interface PhoneInputProps {
8
8
  ccphone?: string;
9
9
  onCcphoneChange?: (value: string) => void;
10
10
  disabled?: boolean;
11
+ readOnly?: boolean;
11
12
  error?: string;
12
13
  placeholder?: string;
13
14
  lockCcphone?: boolean;
14
15
  }
15
- export declare function PhoneInput({ value, onChange, ccphone, onCcphoneChange, disabled, error, placeholder, lockCcphone, }: PhoneInputProps): import("react/jsx-runtime").JSX.Element;
16
+ export declare function PhoneInput({ value, onChange, ccphone, onCcphoneChange, disabled, readOnly, error, placeholder, lockCcphone, }: PhoneInputProps): import("react/jsx-runtime").JSX.Element;
16
17
  export default PhoneInput;
@@ -2,7 +2,7 @@
2
2
  * Signup Modal for @ollaid/native-sso — Design aligned with web SSO
3
3
  * Full signup flow: intro → account-type → info → OTP → password → confirm → success
4
4
  *
5
- * @version 2.1.4
5
+ * @version 2.5.0
6
6
  */
7
7
  import type { UserInfos } from '../types/native';
8
8
  export interface SignupModalProps {
@@ -3,7 +3,7 @@
3
3
  * Lightweight replacements for shadcn/ui components + inline SVG icons
4
4
  * No external dependencies required
5
5
  *
6
- * @version 2.1.4
6
+ * @version 2.5.0
7
7
  */
8
8
  import React from 'react';
9
9
  export declare function IconShieldCheck(props: React.SVGProps<SVGSVGElement>): import("react/jsx-runtime").JSX.Element;
@@ -30,9 +30,11 @@ export declare function Dialog({ open, onOpenChange, children }: {
30
30
  onOpenChange: (open: boolean) => void;
31
31
  children: React.ReactNode;
32
32
  }): import("react/jsx-runtime").JSX.Element | null;
33
- export declare function DialogContent({ children, className }: {
33
+ export declare function DialogContent({ children, className, style, hideCloseButton }: {
34
34
  children: React.ReactNode;
35
35
  className?: string;
36
+ style?: React.CSSProperties;
37
+ hideCloseButton?: boolean;
36
38
  }): import("react/jsx-runtime").JSX.Element;
37
39
  export declare function DialogBody({ children, className, style }: {
38
40
  children: React.ReactNode;
@@ -22,7 +22,7 @@
22
22
  * };
23
23
  * ```
24
24
  *
25
- * @version 2.1.4
25
+ * @version 2.5.0
26
26
  */
27
27
  export interface UseLogoutOptions {
28
28
  /** Callback appelé après une déconnexion réussie (redirection, toast, etc.) */
@@ -2,7 +2,7 @@
2
2
  * Hook de récupération de mot de passe v1.0
3
3
  * Architecture Frontend-First avec appels directs à l'IAM
4
4
  *
5
- * @version 2.1.4
5
+ * @version 2.5.0
6
6
  */
7
7
  export interface UseMobilePasswordOptions {
8
8
  saasApiUrl: string;
@@ -2,7 +2,7 @@
2
2
  * Hook d'inscription Mobile SSO v1.0
3
3
  * Gère le flow: init → verify-otp → complete
4
4
  *
5
- * @version 2.1.4
5
+ * @version 2.5.0
6
6
  */
7
7
  import type { MobileRegistrationFormData, AccountType } from '../types/mobile';
8
8
  interface RegistrationConflict {
@@ -2,7 +2,7 @@
2
2
  * Hook d'authentification Native SSO v1.0
3
3
  * Architecture Frontend-First avec appels directs à l'IAM
4
4
  *
5
- * @version 2.1.4
5
+ * @version 2.5.0
6
6
  */
7
7
  import type { NativeAuthStatus, NativeExchangeResponse, AccountType } from '../types/native';
8
8
  export interface UseNativeAuthOptions {
@@ -10,7 +10,7 @@
10
10
  * - Si 401 → révoque l'IAM (POST /iam/disconnect) + nettoie le frontend
11
11
  * - Ne déconnecte PAS si offline ou serveur inaccessible
12
12
  *
13
- * @version 2.1.4
13
+ * @version 2.5.0
14
14
  */
15
15
  import type { UserInfos } from '../types/native';
16
16
  export interface UseTokenHealthCheckOptions {
@@ -22,6 +22,16 @@ export interface UseTokenHealthCheckOptions {
22
22
  iamApiUrl: string;
23
23
  /** Called when the backend explicitly invalidates the token (401) */
24
24
  onTokenInvalid: () => void;
25
+ /**
26
+ * Optional handler for 401. If provided, it can attempt a refresh and decide
27
+ * whether the session was recovered.
28
+ *
29
+ * Return values:
30
+ * - 'recovered': session is valid again (do NOT call onTokenInvalid)
31
+ * - 'invalid': token is explicitly invalid (call onTokenInvalid)
32
+ * - 'noop': fall back to default behavior
33
+ */
34
+ onUnauthorized?: () => Promise<'recovered' | 'invalid' | 'noop'>;
25
35
  /** Called when fresh user_infos are received */
26
36
  onUserUpdated?: (userInfos: UserInfos) => void;
27
37
  /** Debug mode */