@ollaid/native-sso 2.7.8 → 2.8.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/dist/components/AvatarCropModal.d.ts +1 -1
- package/dist/components/DebugPanel.d.ts +3 -2
- package/dist/components/LoginModal.d.ts +2 -2
- 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/PasswordRedirectModal.d.ts +12 -0
- package/dist/components/SignupModal.d.ts +2 -2
- 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 +3 -3
- package/dist/hooks/useTokenHealthCheck.d.ts +2 -2
- package/dist/index.cjs +309 -21
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +310 -22
- package/dist/index.js.map +1 -1
- package/dist/provider.d.ts +1 -1
- package/dist/services/api.d.ts +5 -5
- 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
|
@@ -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.7.
|
|
5
|
+
* @version 2.7.9
|
|
6
6
|
*/
|
|
7
7
|
export type DebugOnboardingPreset = 'current' | 'photo' | 'phone' | 'email' | 'all';
|
|
8
8
|
interface DebugPanelProps {
|
|
@@ -11,7 +11,8 @@ interface DebugPanelProps {
|
|
|
11
11
|
onOpenLogin?: () => void;
|
|
12
12
|
onOpenSignup?: () => void;
|
|
13
13
|
onOpenOnboarding?: (preset: DebugOnboardingPreset) => void;
|
|
14
|
+
onOpenPassword?: () => void;
|
|
14
15
|
onResetProfilePrompt?: () => void;
|
|
15
16
|
}
|
|
16
|
-
export declare function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onResetProfilePrompt }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
17
|
+
export declare function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onOpenPassword, onResetProfilePrompt }: DebugPanelProps): import("react/jsx-runtime").JSX.Element;
|
|
17
18
|
export default DebugPanel;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Login Modal for @ollaid/native-sso
|
|
3
3
|
* Complete login flow aligned with Native SSO design
|
|
4
4
|
*
|
|
5
|
-
* @version 2.7.
|
|
5
|
+
* @version 2.7.9
|
|
6
6
|
*/
|
|
7
7
|
import type { UserInfos } from '../types/native';
|
|
8
8
|
export interface LoginModalProps {
|
|
@@ -15,7 +15,7 @@ export interface LoginModalProps {
|
|
|
15
15
|
logoUrl?: string;
|
|
16
16
|
loading?: boolean;
|
|
17
17
|
showSwitchToSignup?: boolean;
|
|
18
|
-
/** Type de compte par défaut à persister dans
|
|
18
|
+
/** Type de compte par défaut à persister dans le storage du package */
|
|
19
19
|
defaultAccountType?: 'user' | 'client';
|
|
20
20
|
/** Pre-fill phone number and go directly to phone-input step */
|
|
21
21
|
initialPhone?: string;
|
|
@@ -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.7.
|
|
5
|
+
* @version 2.7.9
|
|
6
6
|
*/
|
|
7
7
|
import type { UserInfos } from '../types/native';
|
|
8
8
|
import type { NativeStorageAdapter } from '../services/api';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
interface PasswordRedirectModalProps {
|
|
2
|
+
open: boolean;
|
|
3
|
+
onOpenChange: (open: boolean) => void;
|
|
4
|
+
saasApiUrl?: string;
|
|
5
|
+
/**
|
|
6
|
+
* @deprecated Gardé pour compatibilité ascendante.
|
|
7
|
+
* Préférer `saasApiUrl` car le flux mot de passe passe désormais par le backend SaaS.
|
|
8
|
+
*/
|
|
9
|
+
iamApiUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
declare const PasswordRedirectModal: ({ open, onOpenChange, saasApiUrl, iamApiUrl }: PasswordRedirectModalProps) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default PasswordRedirectModal;
|
|
@@ -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.7.
|
|
5
|
+
* @version 2.7.9
|
|
6
6
|
*/
|
|
7
7
|
import type { UserInfos } from '../types/native';
|
|
8
8
|
export interface SignupModalProps {
|
|
@@ -13,7 +13,7 @@ export interface SignupModalProps {
|
|
|
13
13
|
saasApiUrl: string;
|
|
14
14
|
iamApiUrl: string;
|
|
15
15
|
logoUrl?: string;
|
|
16
|
-
/** Type de compte par défaut à persister dans
|
|
16
|
+
/** Type de compte par défaut à persister dans le storage du package */
|
|
17
17
|
defaultAccountType?: 'user' | 'client';
|
|
18
18
|
/** Called when conflict resolution wants to switch to login with a pre-filled phone */
|
|
19
19
|
onSwitchToLoginWithPhone?: (phone: string) => void;
|
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.7.
|
|
6
|
+
* @version 2.7.9
|
|
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,10 +2,10 @@
|
|
|
2
2
|
* Hook d'authentification Native SSO v1.0
|
|
3
3
|
* Architecture Frontend-First avec appels directs à l'IAM
|
|
4
4
|
*
|
|
5
|
-
* @version 2.7.
|
|
5
|
+
* @version 2.7.9
|
|
6
6
|
*/
|
|
7
7
|
import { type NativeStorageAdapter } from '../services/api';
|
|
8
|
-
import type { NativeAuthStatus, NativeExchangeResponse, AccountType } from '../types/native';
|
|
8
|
+
import type { NativeAuthStatus, NativeExchangeResponse, AccountType, NativeUser } from '../types/native';
|
|
9
9
|
export interface UseNativeAuthOptions {
|
|
10
10
|
/** URL du Backend SaaS */
|
|
11
11
|
saasApiUrl: string;
|
|
@@ -27,7 +27,7 @@ export declare function useNativeAuth(options: UseNativeAuthOptions): {
|
|
|
27
27
|
credentialsLoaded: boolean;
|
|
28
28
|
processToken: string | null;
|
|
29
29
|
status: NativeAuthStatus | null;
|
|
30
|
-
user:
|
|
30
|
+
user: NativeUser | null;
|
|
31
31
|
application: {
|
|
32
32
|
id: number;
|
|
33
33
|
name: string;
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
*
|
|
7
7
|
* - Premier check 60s après login
|
|
8
8
|
* - Checks suivants toutes les 2 min
|
|
9
|
-
* - Si status === 'connected' → met à jour user_infos
|
|
9
|
+
* - Si status === 'connected' → met à jour user_infos via le storage du package
|
|
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.7.
|
|
13
|
+
* @version 2.7.9
|
|
14
14
|
*/
|
|
15
15
|
import type { UserInfos } from '../types/native';
|
|
16
16
|
export interface UseTokenHealthCheckOptions {
|
package/dist/index.cjs
CHANGED
|
@@ -8890,6 +8890,25 @@ function useTokenHealthCheck(options) {
|
|
|
8890
8890
|
};
|
|
8891
8891
|
}, [enabled, saasApiUrl, performCheck, debug]);
|
|
8892
8892
|
}
|
|
8893
|
+
function normalizeNativeUser(user) {
|
|
8894
|
+
if (!user) return null;
|
|
8895
|
+
const input = user;
|
|
8896
|
+
return {
|
|
8897
|
+
reference: input.reference ?? input.iam_reference ?? input.alias_reference ?? "",
|
|
8898
|
+
name: input.name ?? "",
|
|
8899
|
+
email: input.email ?? void 0,
|
|
8900
|
+
phone: input.phone,
|
|
8901
|
+
ccphone: input.ccphone,
|
|
8902
|
+
image_url: input.image_url ?? input.image,
|
|
8903
|
+
account_type: input.account_type,
|
|
8904
|
+
town: input.town,
|
|
8905
|
+
country: input.country,
|
|
8906
|
+
address: input.address,
|
|
8907
|
+
auth_2fa: input.auth_2fa,
|
|
8908
|
+
alias_reference: input.alias_reference,
|
|
8909
|
+
iam_reference: input.iam_reference
|
|
8910
|
+
};
|
|
8911
|
+
}
|
|
8893
8912
|
function saveSession(exchangeResult, accountType) {
|
|
8894
8913
|
var _a, _b;
|
|
8895
8914
|
const storage = getNativeStorage();
|
|
@@ -9006,7 +9025,8 @@ function useNativeAuth(options) {
|
|
|
9006
9025
|
if (storedRaw) {
|
|
9007
9026
|
try {
|
|
9008
9027
|
const stored = JSON.parse(storedRaw);
|
|
9009
|
-
const merged = { ...stored, ...userInfos };
|
|
9028
|
+
const merged = normalizeNativeUser({ ...stored, ...userInfos });
|
|
9029
|
+
if (!merged) return;
|
|
9010
9030
|
getNativeStorage().setItem(STORAGE.USER, JSON.stringify(merged));
|
|
9011
9031
|
setState((prev) => ({ ...prev, user: merged }));
|
|
9012
9032
|
} catch {
|
|
@@ -9029,13 +9049,10 @@ function useNativeAuth(options) {
|
|
|
9029
9049
|
}
|
|
9030
9050
|
const res = await nativeAuthService.refresh();
|
|
9031
9051
|
if (res.success) {
|
|
9032
|
-
const
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
setState((prev) => ({ ...prev, user, status: "completed" }));
|
|
9037
|
-
} catch {
|
|
9038
|
-
}
|
|
9052
|
+
const snapshot = getSsoSessionSnapshot();
|
|
9053
|
+
const user = normalizeNativeUser(snapshot.user);
|
|
9054
|
+
if (user) {
|
|
9055
|
+
setState((prev) => ({ ...prev, user, status: "completed" }));
|
|
9039
9056
|
}
|
|
9040
9057
|
return "recovered";
|
|
9041
9058
|
}
|
|
@@ -9074,16 +9091,10 @@ function useNativeAuth(options) {
|
|
|
9074
9091
|
return () => clearTimeout(t);
|
|
9075
9092
|
}, [state.status, state.user, tryRefreshSession]);
|
|
9076
9093
|
react.useEffect(() => {
|
|
9077
|
-
const
|
|
9078
|
-
const
|
|
9079
|
-
|
|
9080
|
-
|
|
9081
|
-
try {
|
|
9082
|
-
const user = JSON.parse(storedUser);
|
|
9083
|
-
setState((prev) => ({ ...prev, user, status: "completed" }));
|
|
9084
|
-
} catch {
|
|
9085
|
-
clearSession();
|
|
9086
|
-
}
|
|
9094
|
+
const snapshot = getSsoSessionSnapshot();
|
|
9095
|
+
const user = normalizeNativeUser(snapshot.user);
|
|
9096
|
+
if (snapshot.authToken && user) {
|
|
9097
|
+
setState((prev) => ({ ...prev, user, status: "completed" }));
|
|
9087
9098
|
}
|
|
9088
9099
|
}, []);
|
|
9089
9100
|
react.useEffect(() => {
|
|
@@ -11243,7 +11254,7 @@ function SuccessOrbit() {
|
|
|
11243
11254
|
justifyContent: "center",
|
|
11244
11255
|
zIndex: 2
|
|
11245
11256
|
}, children: /* @__PURE__ */ jsxRuntime.jsx(IconLink, { style: { width: "1.7rem", height: "1.7rem", color: C$1.green } }) }),
|
|
11246
|
-
orbitIcons.map((
|
|
11257
|
+
orbitIcons.map((Icon2, i) => {
|
|
11247
11258
|
const angle = i * 360 / orbitIcons.length;
|
|
11248
11259
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: {
|
|
11249
11260
|
position: "absolute",
|
|
@@ -11262,7 +11273,7 @@ function SuccessOrbit() {
|
|
|
11262
11273
|
display: "flex",
|
|
11263
11274
|
alignItems: "center",
|
|
11264
11275
|
justifyContent: "center"
|
|
11265
|
-
}, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11276
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx(Icon2, { style: { width: "1rem", height: "1rem", color: C$1.gray500 } }) }) }, i);
|
|
11266
11277
|
})
|
|
11267
11278
|
] });
|
|
11268
11279
|
}
|
|
@@ -13300,7 +13311,248 @@ function OnboardingModal({
|
|
|
13300
13311
|
renderConfirmDialog()
|
|
13301
13312
|
] });
|
|
13302
13313
|
}
|
|
13303
|
-
|
|
13314
|
+
/**
|
|
13315
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13316
|
+
*
|
|
13317
|
+
* This source code is licensed under the ISC license.
|
|
13318
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13319
|
+
*/
|
|
13320
|
+
const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
13321
|
+
const mergeClasses = (...classes) => classes.filter((className, index, array) => {
|
|
13322
|
+
return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
|
|
13323
|
+
}).join(" ").trim();
|
|
13324
|
+
/**
|
|
13325
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13326
|
+
*
|
|
13327
|
+
* This source code is licensed under the ISC license.
|
|
13328
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13329
|
+
*/
|
|
13330
|
+
var defaultAttributes = {
|
|
13331
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
13332
|
+
width: 24,
|
|
13333
|
+
height: 24,
|
|
13334
|
+
viewBox: "0 0 24 24",
|
|
13335
|
+
fill: "none",
|
|
13336
|
+
stroke: "currentColor",
|
|
13337
|
+
strokeWidth: 2,
|
|
13338
|
+
strokeLinecap: "round",
|
|
13339
|
+
strokeLinejoin: "round"
|
|
13340
|
+
};
|
|
13341
|
+
/**
|
|
13342
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13343
|
+
*
|
|
13344
|
+
* This source code is licensed under the ISC license.
|
|
13345
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13346
|
+
*/
|
|
13347
|
+
const Icon = react.forwardRef(
|
|
13348
|
+
({
|
|
13349
|
+
color = "currentColor",
|
|
13350
|
+
size = 24,
|
|
13351
|
+
strokeWidth = 2,
|
|
13352
|
+
absoluteStrokeWidth,
|
|
13353
|
+
className = "",
|
|
13354
|
+
children,
|
|
13355
|
+
iconNode,
|
|
13356
|
+
...rest
|
|
13357
|
+
}, ref) => {
|
|
13358
|
+
return react.createElement(
|
|
13359
|
+
"svg",
|
|
13360
|
+
{
|
|
13361
|
+
ref,
|
|
13362
|
+
...defaultAttributes,
|
|
13363
|
+
width: size,
|
|
13364
|
+
height: size,
|
|
13365
|
+
stroke: color,
|
|
13366
|
+
strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
|
13367
|
+
className: mergeClasses("lucide", className),
|
|
13368
|
+
...rest
|
|
13369
|
+
},
|
|
13370
|
+
[
|
|
13371
|
+
...iconNode.map(([tag, attrs]) => react.createElement(tag, attrs)),
|
|
13372
|
+
...Array.isArray(children) ? children : [children]
|
|
13373
|
+
]
|
|
13374
|
+
);
|
|
13375
|
+
}
|
|
13376
|
+
);
|
|
13377
|
+
/**
|
|
13378
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13379
|
+
*
|
|
13380
|
+
* This source code is licensed under the ISC license.
|
|
13381
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13382
|
+
*/
|
|
13383
|
+
const createLucideIcon = (iconName, iconNode) => {
|
|
13384
|
+
const Component = react.forwardRef(
|
|
13385
|
+
({ className, ...props }, ref) => react.createElement(Icon, {
|
|
13386
|
+
ref,
|
|
13387
|
+
iconNode,
|
|
13388
|
+
className: mergeClasses(`lucide-${toKebabCase(iconName)}`, className),
|
|
13389
|
+
...props
|
|
13390
|
+
})
|
|
13391
|
+
);
|
|
13392
|
+
Component.displayName = `${iconName}`;
|
|
13393
|
+
return Component;
|
|
13394
|
+
};
|
|
13395
|
+
/**
|
|
13396
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13397
|
+
*
|
|
13398
|
+
* This source code is licensed under the ISC license.
|
|
13399
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13400
|
+
*/
|
|
13401
|
+
const ExternalLink = createLucideIcon("ExternalLink", [
|
|
13402
|
+
["path", { d: "M15 3h6v6", key: "1q9fwt" }],
|
|
13403
|
+
["path", { d: "M10 14 21 3", key: "gplh6r" }],
|
|
13404
|
+
["path", { d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6", key: "a6xqqp" }]
|
|
13405
|
+
]);
|
|
13406
|
+
/**
|
|
13407
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13408
|
+
*
|
|
13409
|
+
* This source code is licensed under the ISC license.
|
|
13410
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13411
|
+
*/
|
|
13412
|
+
const LoaderCircle = createLucideIcon("LoaderCircle", [
|
|
13413
|
+
["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]
|
|
13414
|
+
]);
|
|
13415
|
+
/**
|
|
13416
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13417
|
+
*
|
|
13418
|
+
* This source code is licensed under the ISC license.
|
|
13419
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13420
|
+
*/
|
|
13421
|
+
const LockKeyhole = createLucideIcon("LockKeyhole", [
|
|
13422
|
+
["circle", { cx: "12", cy: "16", r: "1", key: "1au0dj" }],
|
|
13423
|
+
["rect", { x: "3", y: "10", width: "18", height: "12", rx: "2", key: "6s8ecr" }],
|
|
13424
|
+
["path", { d: "M7 10V7a5 5 0 0 1 10 0v3", key: "1pqi11" }]
|
|
13425
|
+
]);
|
|
13426
|
+
/**
|
|
13427
|
+
* @license lucide-react v0.462.0 - ISC
|
|
13428
|
+
*
|
|
13429
|
+
* This source code is licensed under the ISC license.
|
|
13430
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
13431
|
+
*/
|
|
13432
|
+
const ShieldCheck = createLucideIcon("ShieldCheck", [
|
|
13433
|
+
[
|
|
13434
|
+
"path",
|
|
13435
|
+
{
|
|
13436
|
+
d: "M20 13c0 5-3.5 7.5-7.66 8.95a1 1 0 0 1-.67-.01C7.5 20.5 4 18 4 13V6a1 1 0 0 1 1-1c2 0 4.5-1.2 6.24-2.72a1.17 1.17 0 0 1 1.52 0C14.51 3.81 17 5 19 5a1 1 0 0 1 1 1z",
|
|
13437
|
+
key: "oel41y"
|
|
13438
|
+
}
|
|
13439
|
+
],
|
|
13440
|
+
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
13441
|
+
]);
|
|
13442
|
+
const PasswordRedirectModal = ({ open, onOpenChange, saasApiUrl, iamApiUrl }) => {
|
|
13443
|
+
const [confirmOpen, setConfirmOpen] = react.useState(false);
|
|
13444
|
+
const [loading, setLoading] = react.useState(false);
|
|
13445
|
+
const [errorMessage, setErrorMessage] = react.useState(null);
|
|
13446
|
+
const apiBaseUrl = react.useMemo(() => {
|
|
13447
|
+
const source = saasApiUrl || iamApiUrl;
|
|
13448
|
+
if (!source) {
|
|
13449
|
+
return "";
|
|
13450
|
+
}
|
|
13451
|
+
const normalized = source.replace(/\/$/, "");
|
|
13452
|
+
return normalized.endsWith("/api") ? normalized : `${normalized}/api`;
|
|
13453
|
+
}, [saasApiUrl, iamApiUrl]);
|
|
13454
|
+
const buildUrl = (redirectUrl, magicToken) => {
|
|
13455
|
+
if (redirectUrl) {
|
|
13456
|
+
return redirectUrl;
|
|
13457
|
+
}
|
|
13458
|
+
if (magicToken) {
|
|
13459
|
+
const fallbackUrl = new URL("/auth/auto-connect", "https://iam.ollaid.com");
|
|
13460
|
+
fallbackUrl.searchParams.set("magic_token", magicToken);
|
|
13461
|
+
return fallbackUrl.toString();
|
|
13462
|
+
}
|
|
13463
|
+
return "";
|
|
13464
|
+
};
|
|
13465
|
+
const handleRedirect = async () => {
|
|
13466
|
+
if (loading) return;
|
|
13467
|
+
setLoading(true);
|
|
13468
|
+
setErrorMessage(null);
|
|
13469
|
+
try {
|
|
13470
|
+
const authToken = getAuthToken();
|
|
13471
|
+
const appAccessTokenRef = getNativeStorage().getItem(STORAGE.APP_ACCESS_TOKEN_REF);
|
|
13472
|
+
if (!authToken && !appAccessTokenRef) {
|
|
13473
|
+
throw new Error("Session Native SSO introuvable");
|
|
13474
|
+
}
|
|
13475
|
+
if (!apiBaseUrl) {
|
|
13476
|
+
throw new Error("saasApiUrl non configurée");
|
|
13477
|
+
}
|
|
13478
|
+
const result = await fetchWithTimeout(
|
|
13479
|
+
`${apiBaseUrl}/native/password-link`,
|
|
13480
|
+
{
|
|
13481
|
+
method: "POST",
|
|
13482
|
+
headers: getHeaders(authToken || void 0, true)
|
|
13483
|
+
},
|
|
13484
|
+
2e4
|
|
13485
|
+
);
|
|
13486
|
+
if (!result.success) {
|
|
13487
|
+
throw new Error(result.message || "Impossible de générer le lien");
|
|
13488
|
+
}
|
|
13489
|
+
const redirectUrl = buildUrl(
|
|
13490
|
+
typeof result.redirect_url === "string" && result.redirect_url.length > 0 ? result.redirect_url : typeof result.sso_url === "string" && result.sso_url.length > 0 ? result.sso_url : "",
|
|
13491
|
+
result.magic_token
|
|
13492
|
+
);
|
|
13493
|
+
if (!redirectUrl) {
|
|
13494
|
+
throw new Error("URL de redirection manquante");
|
|
13495
|
+
}
|
|
13496
|
+
window.open(redirectUrl, "_blank", "noopener,noreferrer");
|
|
13497
|
+
onOpenChange(false);
|
|
13498
|
+
setConfirmOpen(false);
|
|
13499
|
+
} catch (error) {
|
|
13500
|
+
const message = error instanceof ApiError ? error.message : (error == null ? void 0 : error.message) || "Impossible de lancer le flux de mot de passe";
|
|
13501
|
+
setErrorMessage(message);
|
|
13502
|
+
} finally {
|
|
13503
|
+
setLoading(false);
|
|
13504
|
+
}
|
|
13505
|
+
};
|
|
13506
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
13507
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { style: { maxWidth: "28rem", borderRadius: "16px", background: "#fff" }, children: [
|
|
13508
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
13509
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { margin: "0 auto 12px", width: 56, height: 56, borderRadius: "50%", background: "rgba(232, 67, 10, 0.1)", display: "flex", alignItems: "center", justifyContent: "center", color: "#e8430a" }, children: /* @__PURE__ */ jsxRuntime.jsx(LockKeyhole, { size: 28 }) }),
|
|
13510
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-center", children: "Mot de passe géré par OLLAID SSO" }),
|
|
13511
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "text-center", children: "Ce bouton sert à tester la redirection vers IAM et l'ouverture du modal de changement de mot de passe." })
|
|
13512
|
+
] }),
|
|
13513
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { border: "1px solid #e5e7eb", borderRadius: 12, padding: 16, background: "#f8fafc", color: "#475569", fontSize: 13, display: "grid", gap: 8 }, children: [
|
|
13514
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "flex-start" }, children: [
|
|
13515
|
+
/* @__PURE__ */ jsxRuntime.jsx(ShieldCheck, { size: 16, color: "#e8430a" }),
|
|
13516
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Le SaaS agit comme relais. Le backend SaaS appelle IAM côté serveur, puis renvoie l'URL de redirection." })
|
|
13517
|
+
] }),
|
|
13518
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 8, alignItems: "flex-start" }, children: [
|
|
13519
|
+
/* @__PURE__ */ jsxRuntime.jsx(ExternalLink, { size: 16, color: "#e8430a" }),
|
|
13520
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: "Une fenêtre IAM va s'ouvrir avec auto-connexion temporaire, sans appel direct du navigateur vers IAM." })
|
|
13521
|
+
] })
|
|
13522
|
+
] }),
|
|
13523
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { style: { gap: 12 }, children: [
|
|
13524
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: () => onOpenChange(false), style: { flex: 1 }, disabled: loading, children: "Fermer" }),
|
|
13525
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: () => setConfirmOpen(true), disabled: loading, style: { flex: 1 }, children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
13526
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 16, style: { marginRight: 8, animation: "spin 1s linear infinite" } }),
|
|
13527
|
+
"Préparation..."
|
|
13528
|
+
] }) : "Changer mon mot de passe" })
|
|
13529
|
+
] })
|
|
13530
|
+
] }) }),
|
|
13531
|
+
/* @__PURE__ */ jsxRuntime.jsx(Dialog, { open: confirmOpen, onOpenChange: (nextOpen) => {
|
|
13532
|
+
if (!loading) {
|
|
13533
|
+
setConfirmOpen(nextOpen);
|
|
13534
|
+
}
|
|
13535
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsxs(DialogContent, { style: { maxWidth: "26rem", borderRadius: "16px", background: "#fff" }, children: [
|
|
13536
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogHeader, { children: [
|
|
13537
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "text-center", children: "Êtes-vous sûr de rediriger vers le SSO ?" }),
|
|
13538
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "text-center", children: "Cette action ouvre IAM dans un nouvel onglet et prépare l'auto-connexion pour tester le changement de mot de passe." })
|
|
13539
|
+
] }),
|
|
13540
|
+
errorMessage && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { border: "1px solid #fecaca", background: "#fef2f2", color: "#b91c1c", borderRadius: 12, padding: 12, fontSize: 13 }, children: errorMessage }),
|
|
13541
|
+
loading && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flexDirection: "column", alignItems: "center", gap: 10, padding: "8px 0 4px" }, children: [
|
|
13542
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 26, style: { animation: "spin 1s linear infinite", color: "#e8430a" } }),
|
|
13543
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 13, color: "#475569", textAlign: "center" }, children: "Création de la session en cours..." })
|
|
13544
|
+
] }),
|
|
13545
|
+
/* @__PURE__ */ jsxRuntime.jsxs(DialogFooter, { style: { gap: 12 }, children: [
|
|
13546
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { variant: "outline", onClick: () => setConfirmOpen(false), style: { flex: 1 }, disabled: loading, children: "Annuler" }),
|
|
13547
|
+
/* @__PURE__ */ jsxRuntime.jsx(Button, { onClick: handleRedirect, style: { flex: 1 }, disabled: loading, children: loading ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
13548
|
+
/* @__PURE__ */ jsxRuntime.jsx(LoaderCircle, { size: 16, style: { marginRight: 8, animation: "spin 1s linear infinite" } }),
|
|
13549
|
+
"Confirmer..."
|
|
13550
|
+
] }) : "Confirmer" })
|
|
13551
|
+
] })
|
|
13552
|
+
] }) })
|
|
13553
|
+
] });
|
|
13554
|
+
};
|
|
13555
|
+
function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOnboarding, onOpenPassword, onResetProfilePrompt }) {
|
|
13304
13556
|
const [logs, setLogs] = react.useState([]);
|
|
13305
13557
|
const [expanded, setExpanded] = react.useState(true);
|
|
13306
13558
|
const [selectedLog, setSelectedLog] = react.useState(null);
|
|
@@ -13440,6 +13692,18 @@ function DebugPanel({ saasApiUrl, iamApiUrl, onOpenLogin, onOpenSignup, onOpenOn
|
|
|
13440
13692
|
children: "Infos profile"
|
|
13441
13693
|
}
|
|
13442
13694
|
),
|
|
13695
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13696
|
+
"button",
|
|
13697
|
+
{
|
|
13698
|
+
onClick: (e) => {
|
|
13699
|
+
e.stopPropagation();
|
|
13700
|
+
onOpenPassword == null ? void 0 : onOpenPassword();
|
|
13701
|
+
},
|
|
13702
|
+
disabled: !onOpenPassword,
|
|
13703
|
+
style: { background: "#334155", color: "#e2e8f0", border: "none", borderRadius: "4px", padding: "2px 8px", cursor: onOpenPassword ? "pointer" : "not-allowed", fontSize: "11px", opacity: onOpenPassword ? 1 : 0.5 },
|
|
13704
|
+
children: "Mot de passe"
|
|
13705
|
+
}
|
|
13706
|
+
),
|
|
13443
13707
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13444
13708
|
"button",
|
|
13445
13709
|
{
|
|
@@ -13633,6 +13897,7 @@ function NativeSSOPage({
|
|
|
13633
13897
|
const [showOnboarding, setShowOnboarding] = react.useState(false);
|
|
13634
13898
|
const [pendingSession, setPendingSession] = react.useState(null);
|
|
13635
13899
|
const [debugOnboardingState, setDebugOnboardingState] = react.useState(null);
|
|
13900
|
+
const [passwordRedirectOpen, setPasswordRedirectOpen] = react.useState(false);
|
|
13636
13901
|
const [redirectingTarget, setRedirectingTarget] = react.useState(null);
|
|
13637
13902
|
const [redirectingReason, setRedirectingReason] = react.useState(null);
|
|
13638
13903
|
const [session, setSession] = react.useState(() => {
|
|
@@ -14005,6 +14270,9 @@ function NativeSSOPage({
|
|
|
14005
14270
|
setShowOnboarding(true);
|
|
14006
14271
|
}
|
|
14007
14272
|
}, [session, clearOnboardingTimers]);
|
|
14273
|
+
const openDebugPassword = react.useCallback(() => {
|
|
14274
|
+
setPasswordRedirectOpen(true);
|
|
14275
|
+
}, []);
|
|
14008
14276
|
react.useEffect(() => {
|
|
14009
14277
|
syncProfilePrompt(session);
|
|
14010
14278
|
return () => {
|
|
@@ -14152,8 +14420,18 @@ function NativeSSOPage({
|
|
|
14152
14420
|
onOpenLogin: openDebugLogin,
|
|
14153
14421
|
onOpenSignup: openDebugSignup,
|
|
14154
14422
|
onOpenOnboarding: openDebugOnboarding,
|
|
14423
|
+
onOpenPassword: openDebugPassword,
|
|
14155
14424
|
onResetProfilePrompt: resetDebugProfilePrompt
|
|
14156
14425
|
}
|
|
14426
|
+
),
|
|
14427
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14428
|
+
PasswordRedirectModal,
|
|
14429
|
+
{
|
|
14430
|
+
open: passwordRedirectOpen,
|
|
14431
|
+
onOpenChange: setPasswordRedirectOpen,
|
|
14432
|
+
saasApiUrl,
|
|
14433
|
+
iamApiUrl
|
|
14434
|
+
}
|
|
14157
14435
|
)
|
|
14158
14436
|
] });
|
|
14159
14437
|
}
|
|
@@ -14233,8 +14511,18 @@ function NativeSSOPage({
|
|
|
14233
14511
|
onOpenLogin: openDebugLogin,
|
|
14234
14512
|
onOpenSignup: openDebugSignup,
|
|
14235
14513
|
onOpenOnboarding: openDebugOnboarding,
|
|
14514
|
+
onOpenPassword: openDebugPassword,
|
|
14236
14515
|
onResetProfilePrompt: resetDebugProfilePrompt
|
|
14237
14516
|
}
|
|
14517
|
+
),
|
|
14518
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
14519
|
+
PasswordRedirectModal,
|
|
14520
|
+
{
|
|
14521
|
+
open: passwordRedirectOpen,
|
|
14522
|
+
onOpenChange: setPasswordRedirectOpen,
|
|
14523
|
+
saasApiUrl,
|
|
14524
|
+
iamApiUrl
|
|
14525
|
+
}
|
|
14238
14526
|
)
|
|
14239
14527
|
] });
|
|
14240
14528
|
}
|