@ollaid/native-sso 2.6.0 → 2.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/AvatarCropModal.d.ts +1 -1
- package/dist/components/DebugPanel.d.ts +1 -1
- package/dist/components/LoginModal.d.ts +1 -1
- package/dist/components/NativeSSOPage.d.ts +1 -1
- package/dist/components/OnboardingModal.d.ts +1 -1
- package/dist/components/PasswordRecoveryModal.d.ts +1 -1
- package/dist/components/SignupModal.d.ts +1 -1
- package/dist/components/ui.d.ts +1 -1
- package/dist/hooks/useLogout.d.ts +1 -1
- package/dist/hooks/useMobilePassword.d.ts +1 -1
- package/dist/hooks/useMobileRegistration.d.ts +1 -1
- package/dist/hooks/useNativeAuth.d.ts +1 -1
- package/dist/hooks/useTokenHealthCheck.d.ts +1 -1
- package/dist/index.cjs +84 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +84 -52
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +1 -1
- package/dist/services/api.d.ts +1 -1
- package/dist/services/debugLogger.d.ts +1 -1
- package/dist/services/iamAccount.d.ts +1 -1
- package/dist/services/mobilePassword.d.ts +1 -1
- package/dist/services/mobileRegistration.d.ts +1 -1
- package/dist/services/nativeAuth.d.ts +1 -1
- package/dist/services/profile.d.ts +1 -1
- package/dist/services/profileChange.d.ts +1 -1
- package/dist/services/profileMedia.d.ts +1 -1
- package/dist/types/mobile.d.ts +1 -1
- package/dist/types/native.d.ts +1 -1
- package/package.json +1 -1
- package/README.md +0 -2689
|
@@ -2,7 +2,7 @@
|
|
|
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.
|
|
5
|
+
* @version 2.7.0
|
|
6
6
|
*/
|
|
7
7
|
export type DebugOnboardingPreset = 'current' | 'photo' | 'phone' | 'email' | 'all';
|
|
8
8
|
interface DebugPanelProps {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* NativeSSOPage — Page autonome complète pour @ollaid/native-sso
|
|
3
3
|
* Design aligné sur le parcours Native SSO (fond primary, card blanche, ShieldCheck branding)
|
|
4
4
|
*
|
|
5
|
-
* @version 2.
|
|
5
|
+
* @version 2.7.0
|
|
6
6
|
*/
|
|
7
7
|
import type { UserInfos } from '../types/native';
|
|
8
8
|
import type { NativeStorageAdapter } from '../services/api';
|
|
@@ -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.
|
|
5
|
+
* @version 2.7.0
|
|
6
6
|
*/
|
|
7
7
|
import type { UserInfos } from '../types/native';
|
|
8
8
|
export interface SignupModalProps {
|
package/dist/components/ui.d.ts
CHANGED
|
@@ -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.
|
|
6
|
+
* @version 2.7.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;
|
|
@@ -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.
|
|
5
|
+
* @version 2.7.0
|
|
6
6
|
*/
|
|
7
7
|
import { type NativeStorageAdapter } from '../services/api';
|
|
8
8
|
import type { NativeAuthStatus, NativeExchangeResponse, AccountType } from '../types/native';
|
|
@@ -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.
|
|
13
|
+
* @version 2.7.0
|
|
14
14
|
*/
|
|
15
15
|
import type { UserInfos } from '../types/native';
|
|
16
16
|
export interface UseTokenHealthCheckOptions {
|
package/dist/index.cjs
CHANGED
|
@@ -291,17 +291,18 @@ function OTPInput({
|
|
|
291
291
|
disabled = false,
|
|
292
292
|
autoFocus = true
|
|
293
293
|
}) {
|
|
294
|
+
const safeLength = Number.isFinite(length) ? Math.max(1, Math.min(12, Math.trunc(length))) : 6;
|
|
294
295
|
const inputRefs = react.useRef([]);
|
|
295
296
|
const [activeIndex, setActiveIndex] = react.useState(0);
|
|
296
297
|
react.useEffect(() => {
|
|
297
|
-
inputRefs.current = inputRefs.current.slice(0,
|
|
298
|
-
}, [
|
|
298
|
+
inputRefs.current = inputRefs.current.slice(0, safeLength);
|
|
299
|
+
}, [safeLength]);
|
|
299
300
|
react.useEffect(() => {
|
|
300
301
|
if (autoFocus && inputRefs.current[0]) inputRefs.current[0].focus();
|
|
301
302
|
}, [autoFocus]);
|
|
302
303
|
react.useEffect(() => {
|
|
303
|
-
if (value.length ===
|
|
304
|
-
}, [value,
|
|
304
|
+
if (value.length === safeLength && onComplete) onComplete(value);
|
|
305
|
+
}, [value, safeLength, onComplete]);
|
|
305
306
|
const handleChange = (index, char) => {
|
|
306
307
|
var _a;
|
|
307
308
|
if (disabled) return;
|
|
@@ -309,8 +310,8 @@ function OTPInput({
|
|
|
309
310
|
if (!digit) return;
|
|
310
311
|
const newValue = value.split("");
|
|
311
312
|
newValue[index] = digit;
|
|
312
|
-
onChange(newValue.join("").slice(0,
|
|
313
|
-
if (index <
|
|
313
|
+
onChange(newValue.join("").slice(0, safeLength));
|
|
314
|
+
if (index < safeLength - 1) {
|
|
314
315
|
(_a = inputRefs.current[index + 1]) == null ? void 0 : _a.focus();
|
|
315
316
|
setActiveIndex(index + 1);
|
|
316
317
|
}
|
|
@@ -333,7 +334,7 @@ function OTPInput({
|
|
|
333
334
|
} else if (e.key === "ArrowLeft" && index > 0) {
|
|
334
335
|
(_b = inputRefs.current[index - 1]) == null ? void 0 : _b.focus();
|
|
335
336
|
setActiveIndex(index - 1);
|
|
336
|
-
} else if (e.key === "ArrowRight" && index <
|
|
337
|
+
} else if (e.key === "ArrowRight" && index < safeLength - 1) {
|
|
337
338
|
(_c = inputRefs.current[index + 1]) == null ? void 0 : _c.focus();
|
|
338
339
|
setActiveIndex(index + 1);
|
|
339
340
|
}
|
|
@@ -344,14 +345,14 @@ function OTPInput({
|
|
|
344
345
|
e.preventDefault();
|
|
345
346
|
const pasted = e.clipboardData.getData("text").replace(/[^0-9]/g, "");
|
|
346
347
|
if (pasted) {
|
|
347
|
-
const newValue = pasted.slice(0,
|
|
348
|
+
const newValue = pasted.slice(0, safeLength);
|
|
348
349
|
onChange(newValue);
|
|
349
|
-
const focusIndex = Math.min(newValue.length,
|
|
350
|
+
const focusIndex = Math.min(newValue.length, safeLength - 1);
|
|
350
351
|
(_a = inputRefs.current[focusIndex]) == null ? void 0 : _a.focus();
|
|
351
352
|
setActiveIndex(focusIndex);
|
|
352
353
|
}
|
|
353
354
|
};
|
|
354
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem" }, children: Array.from({ length }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
355
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: "0.5rem" }, children: Array.from({ length: safeLength }).map((_, index) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
355
356
|
"input",
|
|
356
357
|
{
|
|
357
358
|
ref: (el) => inputRefs.current[index] = el,
|
|
@@ -7557,8 +7558,12 @@ function getHeaders(token, includeConfigPrefix = false) {
|
|
|
7557
7558
|
let credentials = null;
|
|
7558
7559
|
let credentialsLoadedAt = 0;
|
|
7559
7560
|
let credentialsTtl = 300;
|
|
7561
|
+
let refreshInFlight = null;
|
|
7562
|
+
let lastSuccessfulRefreshAt = 0;
|
|
7563
|
+
let lastSuccessfulRefreshResponse = null;
|
|
7560
7564
|
const DEFAULT_TTL = 300;
|
|
7561
7565
|
const REFRESH_MARGIN = 30;
|
|
7566
|
+
const REFRESH_COOLDOWN_MS = 60 * 1e3;
|
|
7562
7567
|
const nativeAuthService = {
|
|
7563
7568
|
hasCredentials() {
|
|
7564
7569
|
return credentials !== null;
|
|
@@ -7857,6 +7862,16 @@ const nativeAuthService = {
|
|
|
7857
7862
|
}
|
|
7858
7863
|
},
|
|
7859
7864
|
async refresh() {
|
|
7865
|
+
const now = Date.now();
|
|
7866
|
+
if (refreshInFlight) {
|
|
7867
|
+
return refreshInFlight;
|
|
7868
|
+
}
|
|
7869
|
+
if ((lastSuccessfulRefreshResponse == null ? void 0 : lastSuccessfulRefreshResponse.success) && lastSuccessfulRefreshAt && now - lastSuccessfulRefreshAt < REFRESH_COOLDOWN_MS) {
|
|
7870
|
+
if (isDebugMode()) {
|
|
7871
|
+
console.log("🔄 [SaaS] POST /native/refresh — cooldown actif, réponse réutilisée");
|
|
7872
|
+
}
|
|
7873
|
+
return lastSuccessfulRefreshResponse;
|
|
7874
|
+
}
|
|
7860
7875
|
const cfg = getNativeAuthConfig();
|
|
7861
7876
|
if (!cfg.saasApiUrl) {
|
|
7862
7877
|
throw new ApiError("saasApiUrl non configurée", "unknown");
|
|
@@ -7869,51 +7884,62 @@ const nativeAuthService = {
|
|
|
7869
7884
|
if (isDebugMode()) {
|
|
7870
7885
|
console.log("📤 [SaaS] POST /native/refresh");
|
|
7871
7886
|
}
|
|
7872
|
-
|
|
7873
|
-
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
|
|
7886
|
-
|
|
7887
|
-
|
|
7888
|
-
|
|
7889
|
-
|
|
7890
|
-
|
|
7887
|
+
refreshInFlight = (async () => {
|
|
7888
|
+
try {
|
|
7889
|
+
let response;
|
|
7890
|
+
try {
|
|
7891
|
+
response = await fetchWithTimeout(
|
|
7892
|
+
`${cfg.saasApiUrl}/native/refresh`,
|
|
7893
|
+
{
|
|
7894
|
+
method: "POST",
|
|
7895
|
+
headers: getHeaders(void 0, true),
|
|
7896
|
+
body: JSON.stringify({ refresh_token: refreshToken })
|
|
7897
|
+
},
|
|
7898
|
+
cfg.timeout || 3e4
|
|
7899
|
+
);
|
|
7900
|
+
} catch (err) {
|
|
7901
|
+
if (err instanceof ApiError) {
|
|
7902
|
+
if (err.statusCode === 401) {
|
|
7903
|
+
response = {
|
|
7904
|
+
success: false,
|
|
7905
|
+
error_type: err.errorType || "invalid_refresh",
|
|
7906
|
+
message: err.message
|
|
7907
|
+
};
|
|
7908
|
+
} else if (err.statusCode === 404) {
|
|
7909
|
+
response = {
|
|
7910
|
+
success: false,
|
|
7911
|
+
error_type: "not_supported",
|
|
7912
|
+
message: "Endpoint refresh non disponible sur ce SaaS"
|
|
7913
|
+
};
|
|
7914
|
+
} else {
|
|
7915
|
+
throw err;
|
|
7916
|
+
}
|
|
7917
|
+
} else {
|
|
7918
|
+
throw err;
|
|
7919
|
+
}
|
|
7891
7920
|
}
|
|
7892
|
-
if (
|
|
7893
|
-
|
|
7894
|
-
|
|
7895
|
-
|
|
7896
|
-
|
|
7897
|
-
|
|
7921
|
+
if (response.success) {
|
|
7922
|
+
if (response.token) {
|
|
7923
|
+
setAuthToken(response.token);
|
|
7924
|
+
}
|
|
7925
|
+
const storage = getNativeStorage();
|
|
7926
|
+
if (response.expires_at) storage.setItem(STORAGE.TOKEN_EXPIRES_AT, response.expires_at);
|
|
7927
|
+
if (response.refresh_token) storage.setItem(STORAGE.REFRESH_TOKEN, response.refresh_token);
|
|
7928
|
+
if (response.refresh_expires_at) storage.setItem(STORAGE.REFRESH_EXPIRES_AT, response.refresh_expires_at);
|
|
7929
|
+
if (response.app_access_token_ref) storage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, response.app_access_token_ref);
|
|
7930
|
+
if (response.alias_reference) storage.setItem(STORAGE.ALIAS_REFERENCE, response.alias_reference);
|
|
7931
|
+
if (response.user) {
|
|
7932
|
+
setAuthUser(response.user);
|
|
7933
|
+
}
|
|
7934
|
+
lastSuccessfulRefreshAt = Date.now();
|
|
7935
|
+
lastSuccessfulRefreshResponse = response;
|
|
7898
7936
|
}
|
|
7937
|
+
return response;
|
|
7938
|
+
} finally {
|
|
7939
|
+
refreshInFlight = null;
|
|
7899
7940
|
}
|
|
7900
|
-
|
|
7901
|
-
|
|
7902
|
-
if (response.success) {
|
|
7903
|
-
if (response.token) {
|
|
7904
|
-
setAuthToken(response.token);
|
|
7905
|
-
}
|
|
7906
|
-
const storage = getNativeStorage();
|
|
7907
|
-
if (response.expires_at) storage.setItem(STORAGE.TOKEN_EXPIRES_AT, response.expires_at);
|
|
7908
|
-
if (response.refresh_token) storage.setItem(STORAGE.REFRESH_TOKEN, response.refresh_token);
|
|
7909
|
-
if (response.refresh_expires_at) storage.setItem(STORAGE.REFRESH_EXPIRES_AT, response.refresh_expires_at);
|
|
7910
|
-
if (response.app_access_token_ref) storage.setItem(STORAGE.APP_ACCESS_TOKEN_REF, response.app_access_token_ref);
|
|
7911
|
-
if (response.alias_reference) storage.setItem(STORAGE.ALIAS_REFERENCE, response.alias_reference);
|
|
7912
|
-
if (response.user) {
|
|
7913
|
-
setAuthUser(response.user);
|
|
7914
|
-
}
|
|
7915
|
-
}
|
|
7916
|
-
return response;
|
|
7941
|
+
})();
|
|
7942
|
+
return refreshInFlight;
|
|
7917
7943
|
},
|
|
7918
7944
|
async logout(token) {
|
|
7919
7945
|
const config2 = getNativeAuthConfig();
|
|
@@ -7962,11 +7988,17 @@ const nativeAuthService = {
|
|
|
7962
7988
|
clearAuthToken();
|
|
7963
7989
|
credentials = null;
|
|
7964
7990
|
credentialsLoadedAt = 0;
|
|
7991
|
+
refreshInFlight = null;
|
|
7992
|
+
lastSuccessfulRefreshAt = 0;
|
|
7993
|
+
lastSuccessfulRefreshResponse = null;
|
|
7965
7994
|
return { success: true };
|
|
7966
7995
|
},
|
|
7967
7996
|
clearCredentials() {
|
|
7968
7997
|
credentials = null;
|
|
7969
7998
|
credentialsLoadedAt = 0;
|
|
7999
|
+
refreshInFlight = null;
|
|
8000
|
+
lastSuccessfulRefreshAt = 0;
|
|
8001
|
+
lastSuccessfulRefreshResponse = null;
|
|
7970
8002
|
},
|
|
7971
8003
|
// ============================================
|
|
7972
8004
|
// High-level methods
|