@iqauth/sdk 2.0.5 → 2.2.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 +19 -3
- package/dist/browser.d.mts +2 -2
- package/dist/browser.d.ts +2 -2
- package/dist/browser.js +57 -6
- package/dist/browser.mjs +2 -2
- package/dist/{chunk-ZESHDJDU.mjs → chunk-D72UL5HL.mjs} +3 -6
- package/dist/{chunk-JQRTY5MY.mjs → chunk-M4J6BPK7.mjs} +3 -8
- package/dist/chunk-QEJB7WEQ.mjs +119 -0
- package/dist/{chunk-S3M2IXCE.mjs → chunk-QZB745C2.mjs} +3 -8
- package/dist/cli/index.js +21 -0
- package/dist/cli/index.mjs +1 -1
- package/dist/{doctor-OHJRZBBT.mjs → doctor-XCI77BQS.mjs} +2 -1
- package/dist/express.js +54 -25
- package/dist/express.mjs +5 -8
- package/dist/fastify.js +53 -19
- package/dist/fastify.mjs +4 -5
- package/dist/hono.js +53 -19
- package/dist/hono.mjs +4 -5
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +59 -4
- package/dist/index.mjs +4 -2
- package/dist/next.js +66 -34
- package/dist/next.mjs +6 -9
- package/dist/{publishableKey-B5DIK81A.d.mts → publishableKey-BaR0HoAH.d.mts} +10 -1
- package/dist/{publishableKey-B5DIK81A.d.ts → publishableKey-BaR0HoAH.d.ts} +10 -1
- package/dist/react.d.mts +91 -4
- package/dist/react.d.ts +91 -4
- package/dist/react.js +466 -162
- package/dist/react.mjs +411 -147
- package/dist/server/handlers.js +63 -17
- package/dist/server/handlers.mjs +3 -2
- package/dist/server.js +53 -21
- package/dist/server.mjs +3 -3
- package/dist/{signIn-VRNzlNyG.d.ts → signIn-BVDTIA_t.d.ts} +1 -1
- package/dist/{signIn-CEMdUAwd.d.mts → signIn-D_kP3v-c.d.mts} +1 -1
- package/package.json +1 -1
- package/dist/chunk-5WFR6Y33.mjs +0 -59
package/dist/react.js
CHANGED
|
@@ -21,6 +21,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var react_exports = {};
|
|
22
22
|
__export(react_exports, {
|
|
23
23
|
AuthCallback: () => AuthCallback,
|
|
24
|
+
IQAuthLoaded: () => IQAuthLoaded,
|
|
25
|
+
IQAuthLoading: () => IQAuthLoading,
|
|
24
26
|
IQAuthProvider: () => IQAuthProvider,
|
|
25
27
|
OrganizationSwitcher: () => OrganizationSwitcher,
|
|
26
28
|
RedirectToSignIn: () => RedirectToSignIn,
|
|
@@ -31,10 +33,13 @@ __export(react_exports, {
|
|
|
31
33
|
UserButton: () => UserButton,
|
|
32
34
|
UserProfile: () => UserProfile,
|
|
33
35
|
__version__: () => __version__,
|
|
36
|
+
isSilentSsoEligible: () => isSilentSsoEligible,
|
|
37
|
+
sanitizeBrandCss: () => sanitizeBrandCss,
|
|
34
38
|
useAuth: () => useAuth,
|
|
35
39
|
useAuthFetch: () => useAuthFetch,
|
|
36
40
|
useIQAuthSignInContext: () => useIQAuthSignInContext,
|
|
37
41
|
useOrganization: () => useOrganization,
|
|
42
|
+
useResolvedSdkBranding: () => useResolvedSdkBranding,
|
|
38
43
|
useSession: () => useSession,
|
|
39
44
|
useUser: () => useUser
|
|
40
45
|
});
|
|
@@ -67,20 +72,60 @@ function b64urlDecode(input) {
|
|
|
67
72
|
const { Buffer: Buffer2 } = require("buffer");
|
|
68
73
|
return Buffer2.from(normalized, "base64").toString("utf8");
|
|
69
74
|
}
|
|
70
|
-
function
|
|
71
|
-
if (typeof
|
|
72
|
-
|
|
73
|
-
if (!m) return null;
|
|
75
|
+
function isValidIssuerUrl(iss) {
|
|
76
|
+
if (typeof iss !== "string" || iss.length === 0) return false;
|
|
77
|
+
if (!iss.startsWith("http://") && !iss.startsWith("https://")) return false;
|
|
74
78
|
try {
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
77
|
-
if (
|
|
78
|
-
|
|
79
|
-
}
|
|
80
|
-
return { mode: m[1], iss: json.iss, appId: json.appId, tenantId: json.tenantId, kid: json.kid, raw };
|
|
79
|
+
const u = new URL(iss);
|
|
80
|
+
if (u.protocol !== "http:" && u.protocol !== "https:") return false;
|
|
81
|
+
if (!u.hostname) return false;
|
|
82
|
+
return true;
|
|
81
83
|
} catch {
|
|
82
|
-
return
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
function assertPublishableKey(raw, opts) {
|
|
88
|
+
const ctx = opts?.context ? `${opts.context}: ` : "";
|
|
89
|
+
if (typeof raw !== "string" || raw.length === 0) {
|
|
90
|
+
throw new IQAuthError(
|
|
91
|
+
"CONFIG_INVALID",
|
|
92
|
+
`${ctx}IQAuth publishable key is missing. Set IQAUTH_PUBLISHABLE_KEY (or pass publishableKey) to a pk_test_\u2026 or pk_live_\u2026 value from the IQAuth admin console.`
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
const shapeMatch = raw.match(/^pk_(test|live)_([A-Za-z0-9_-]+)$/);
|
|
96
|
+
if (!shapeMatch) {
|
|
97
|
+
throw new IQAuthError(
|
|
98
|
+
"CONFIG_INVALID",
|
|
99
|
+
`${ctx}IQAuth publishable key is malformed (got ${raw.slice(0, 12)}\u2026). Expected pk_test_\u2026 or pk_live_\u2026; regenerate the key from the IQAuth admin console.`
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
let decoded;
|
|
103
|
+
try {
|
|
104
|
+
decoded = JSON.parse(b64urlDecode(shapeMatch[2]));
|
|
105
|
+
} catch {
|
|
106
|
+
throw new IQAuthError(
|
|
107
|
+
"CONFIG_INVALID",
|
|
108
|
+
`${ctx}IQAuth publishable key payload is not valid base64url JSON. Regenerate the key from the IQAuth admin console.`
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
if (!isPublishableKeyPayload(decoded)) {
|
|
112
|
+
throw new IQAuthError(
|
|
113
|
+
"CONFIG_INVALID",
|
|
114
|
+
`${ctx}IQAuth publishable key payload is missing required fields {iss, appId, tenantId, kid}. Regenerate the key from the IQAuth admin console.`
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
if (!isValidIssuerUrl(decoded.iss)) {
|
|
118
|
+
throw new IQAuthError(
|
|
119
|
+
"CONFIG_INVALID",
|
|
120
|
+
`${ctx}IQAuth publishable key encodes an invalid issuer (iss=${JSON.stringify(decoded.iss)}). Expected a fully-qualified URL like "https://auth.example.com" (scheme required). Regenerate the key from the IQAuth admin console, or set IQAUTH_ISSUER to the correct issuer URL as a temporary workaround.`
|
|
121
|
+
);
|
|
83
122
|
}
|
|
123
|
+
return { mode: shapeMatch[1], iss: decoded.iss, appId: decoded.appId, tenantId: decoded.tenantId, kid: decoded.kid, raw };
|
|
124
|
+
}
|
|
125
|
+
function isPublishableKeyPayload(value) {
|
|
126
|
+
if (!value || typeof value !== "object") return false;
|
|
127
|
+
const v = value;
|
|
128
|
+
return typeof v.iss === "string" && typeof v.appId === "string" && typeof v.tenantId === "string" && typeof v.kid === "string";
|
|
84
129
|
}
|
|
85
130
|
|
|
86
131
|
// src/browser/storage.ts
|
|
@@ -203,12 +248,7 @@ var SessionManager = class {
|
|
|
203
248
|
this.remoteRefreshWaiters = [];
|
|
204
249
|
/** Active claims by other tabs (keyed by source tabId). */
|
|
205
250
|
this.foreignClaim = null;
|
|
206
|
-
const parsed =
|
|
207
|
-
if (!parsed) {
|
|
208
|
-
throw new Error(
|
|
209
|
-
`Invalid IQAuth publishable key. Expected pk_test_\u2026 or pk_live_\u2026 (got ${options.publishableKey?.slice(0, 12) ?? "<empty>"}\u2026).`
|
|
210
|
-
);
|
|
211
|
-
}
|
|
251
|
+
const parsed = assertPublishableKey(options.publishableKey, { context: "@iqauth/sdk/browser SessionManager" });
|
|
212
252
|
this.key = parsed;
|
|
213
253
|
const inferred = options.issuer ?? (parsed.iss.startsWith("http") ? parsed.iss : `https://${parsed.iss}`);
|
|
214
254
|
this.issuer = inferred.replace(/\/+$/, "");
|
|
@@ -843,6 +883,16 @@ function SignedOut({ children }) {
|
|
|
843
883
|
if (!isLoaded || isSignedIn) return null;
|
|
844
884
|
return (0, import_react.createElement)(import_react.Fragment, null, children);
|
|
845
885
|
}
|
|
886
|
+
function IQAuthLoading({ children }) {
|
|
887
|
+
const { isLoaded } = useAuth();
|
|
888
|
+
if (isLoaded) return null;
|
|
889
|
+
return (0, import_react.createElement)(import_react.Fragment, null, children);
|
|
890
|
+
}
|
|
891
|
+
function IQAuthLoaded({ children }) {
|
|
892
|
+
const { isLoaded } = useAuth();
|
|
893
|
+
if (!isLoaded) return null;
|
|
894
|
+
return (0, import_react.createElement)(import_react.Fragment, null, children);
|
|
895
|
+
}
|
|
846
896
|
function RedirectToSignIn(props = {}) {
|
|
847
897
|
const { manager, snapshot } = useCtx();
|
|
848
898
|
const [error, setError] = (0, import_react.useState)(null);
|
|
@@ -911,6 +961,12 @@ function brandStyle(branding) {
|
|
|
911
961
|
if (branding.backgroundColor) s["--brand-bg"] = branding.backgroundColor;
|
|
912
962
|
if (branding.surfaceColor) s["--brand-surface"] = branding.surfaceColor;
|
|
913
963
|
if (branding.textColor) s["--brand-text"] = branding.textColor;
|
|
964
|
+
if (branding.borderRadius != null && branding.borderRadius !== "") {
|
|
965
|
+
const n = typeof branding.borderRadius === "number" ? `${branding.borderRadius}px` : String(branding.borderRadius);
|
|
966
|
+
s["--brand-radius"] = n;
|
|
967
|
+
}
|
|
968
|
+
if (branding.fontFamilyBody) s["--brand-font-body"] = branding.fontFamilyBody;
|
|
969
|
+
if (branding.fontFamilyHeading) s["--brand-font-heading"] = branding.fontFamilyHeading;
|
|
914
970
|
return s;
|
|
915
971
|
}
|
|
916
972
|
async function jsonFetch(url, init) {
|
|
@@ -935,7 +991,7 @@ function useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo) {
|
|
|
935
991
|
let cancelled = false;
|
|
936
992
|
setLoading(true);
|
|
937
993
|
const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/public/apps/${encodeURIComponent(appKey)}/sign-in-context?return_to=${encodeURIComponent(returnTo)}`;
|
|
938
|
-
fetch(url).then((r) => r.json()).then((payload) => {
|
|
994
|
+
fetch(url, { credentials: "include" }).then((r) => r.json()).then((payload) => {
|
|
939
995
|
if (cancelled) return;
|
|
940
996
|
if (payload?.success === false) throw new Error(payload?.error?.message || "Failed to load sign-in context");
|
|
941
997
|
setCtx(payload.data);
|
|
@@ -953,6 +1009,7 @@ function useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo) {
|
|
|
953
1009
|
var SHELL_CSS = `
|
|
954
1010
|
.iqauth-sdk-shell {
|
|
955
1011
|
min-height: 100vh;
|
|
1012
|
+
width: 100%;
|
|
956
1013
|
display: grid;
|
|
957
1014
|
grid-template-columns: 1fr;
|
|
958
1015
|
background: var(--brand-bg, #f7f7f6);
|
|
@@ -961,20 +1018,31 @@ var SHELL_CSS = `
|
|
|
961
1018
|
.iqauth-sdk-hero { display: none; }
|
|
962
1019
|
.iqauth-sdk-pane {
|
|
963
1020
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
964
|
-
padding:
|
|
1021
|
+
padding: 48px 24px; min-height: 100vh;
|
|
965
1022
|
}
|
|
966
1023
|
.iqauth-sdk-card {
|
|
967
|
-
width: 100%; max-width:
|
|
1024
|
+
width: 100%; max-width: 460px;
|
|
968
1025
|
background: var(--brand-surface, #ffffff);
|
|
969
1026
|
border: 1px solid rgba(15,23,42,0.08);
|
|
970
|
-
border-radius:
|
|
971
|
-
box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0
|
|
1027
|
+
border-radius: var(--brand-radius, 16px);
|
|
1028
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 12px 32px rgba(15,23,42,0.06);
|
|
972
1029
|
overflow: hidden;
|
|
973
1030
|
}
|
|
974
|
-
.iqauth-sdk-
|
|
975
|
-
.iqauth-sdk-
|
|
1031
|
+
.iqauth-sdk-shell, .iqauth-sdk-shell input, .iqauth-sdk-shell button { font-family: var(--brand-font-body, inherit); }
|
|
1032
|
+
.iqauth-sdk-shell h1, .iqauth-sdk-shell h2, .iqauth-sdk-shell h3 { font-family: var(--brand-font-heading, var(--brand-font-body, inherit)); }
|
|
1033
|
+
.iqauth-sdk-shell[data-layout="centered_card"] { grid-template-columns: 1fr; }
|
|
1034
|
+
.iqauth-sdk-shell[data-layout="centered_card"] .iqauth-sdk-hero { display: none; }
|
|
1035
|
+
.iqauth-sdk-shell[data-layout="full_bleed"] { background-size: cover; background-position: center; background-repeat: no-repeat; }
|
|
1036
|
+
.iqauth-sdk-shell[data-layout="full_bleed"] .iqauth-sdk-hero { display: none; }
|
|
1037
|
+
.iqauth-sdk-shell[data-layout="full_bleed"] .iqauth-sdk-pane { background: rgba(15,23,42,0.30); }
|
|
1038
|
+
.iqauth-sdk-shell[data-social-style="outline"] .iqauth-sdk-google-btn { background: transparent; border-color: var(--brand-primary, rgba(15,23,42,0.18)); color: var(--brand-text, inherit); }
|
|
1039
|
+
.iqauth-sdk-shell[data-social-style="ghost"] .iqauth-sdk-google-btn { background: transparent; border-color: transparent; color: var(--brand-text, inherit); }
|
|
1040
|
+
.iqauth-sdk-shell[data-social-style="solid"] .iqauth-sdk-google-btn { background: var(--brand-primary, #3b82f6); border-color: transparent; color: #fff; }
|
|
1041
|
+
.iqauth-sdk-shell[data-social-style="solid"] .iqauth-sdk-google-btn:hover { background: var(--brand-primary, #3b82f6); opacity: 0.92; }
|
|
1042
|
+
.iqauth-sdk-card-header { padding: 32px 36px 0; }
|
|
1043
|
+
.iqauth-sdk-card-header h1 { font-size: 24px; font-weight: 600; margin: 0; line-height: 1.2; letter-spacing: -0.01em; }
|
|
976
1044
|
.iqauth-sdk-card-header p { margin: 8px 0 0; font-size: 14px; color: rgba(15,23,42,0.65); line-height: 1.5; }
|
|
977
|
-
.iqauth-sdk-card-body { padding:
|
|
1045
|
+
.iqauth-sdk-card-body { padding: 32px 36px 28px; display: flex; flex-direction: column; gap: 18px; }
|
|
978
1046
|
.iqauth-sdk-mobile-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; }
|
|
979
1047
|
.iqauth-sdk-mobile-brand img { height: 36px; width: auto; }
|
|
980
1048
|
.iqauth-sdk-mobile-brand span { font-size: 16px; font-weight: 600; }
|
|
@@ -995,11 +1063,11 @@ var SHELL_CSS = `
|
|
|
995
1063
|
.iqauth-sdk-google-btn:hover { background: #f8fafc; border-color: rgba(15,23,42,0.28); }
|
|
996
1064
|
.iqauth-sdk-google-btn[disabled] { opacity: 0.6; cursor: not-allowed; }
|
|
997
1065
|
|
|
998
|
-
@media (min-width:
|
|
999
|
-
.iqauth-sdk-shell { grid-template-columns: minmax(0,
|
|
1066
|
+
@media (min-width: 768px) {
|
|
1067
|
+
.iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
|
|
1000
1068
|
.iqauth-sdk-hero {
|
|
1001
1069
|
display: flex; flex-direction: column; justify-content: space-between;
|
|
1002
|
-
padding:
|
|
1070
|
+
padding: clamp(32px, 4vw, 56px); color: #ffffff;
|
|
1003
1071
|
background: linear-gradient(135deg, var(--brand-primary, #3b82f6) 0%, var(--brand-accent, #6366f1) 100%);
|
|
1004
1072
|
background-size: cover; background-position: center;
|
|
1005
1073
|
position: relative; overflow: hidden; min-height: 100vh;
|
|
@@ -1008,15 +1076,113 @@ var SHELL_CSS = `
|
|
|
1008
1076
|
background-image: var(--iqauth-sdk-hero-image), linear-gradient(135deg, var(--brand-primary, #3b82f6), var(--brand-accent, #6366f1));
|
|
1009
1077
|
background-blend-mode: multiply;
|
|
1010
1078
|
}
|
|
1011
|
-
.iqauth-sdk-hero-brand img { height:
|
|
1012
|
-
.iqauth-sdk-hero-brand .iqauth-sdk-hero-name { font-size:
|
|
1013
|
-
.iqauth-sdk-hero-content
|
|
1014
|
-
.iqauth-sdk-hero-content
|
|
1079
|
+
.iqauth-sdk-hero-brand img { height: 40px; width: auto; filter: brightness(0) invert(1); opacity: 0.96; }
|
|
1080
|
+
.iqauth-sdk-hero-brand .iqauth-sdk-hero-name { font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
|
|
1081
|
+
.iqauth-sdk-hero-content { max-width: 520px; }
|
|
1082
|
+
.iqauth-sdk-hero-content h2 { font-size: clamp(24px, 2.4vw, 34px); font-weight: 600; line-height: 1.2; margin: 0 0 14px; letter-spacing: -0.015em; word-wrap: break-word; overflow-wrap: break-word; hyphens: auto; }
|
|
1083
|
+
.iqauth-sdk-hero-content p { font-size: 15px; line-height: 1.6; opacity: 0.92; margin: 0; white-space: pre-wrap; }
|
|
1015
1084
|
.iqauth-sdk-hero-foot { font-size: 12px; opacity: 0.7; }
|
|
1016
1085
|
.iqauth-sdk-mobile-brand { display: none; }
|
|
1017
1086
|
}
|
|
1087
|
+
@media (min-width: 1280px) {
|
|
1088
|
+
.iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
|
|
1089
|
+
}
|
|
1018
1090
|
`;
|
|
1019
1091
|
var sdkShellStylesInjected = false;
|
|
1092
|
+
var SDK_CSS_MAX_LEN = 50 * 1024;
|
|
1093
|
+
var SDK_CSS_FORBIDDEN = [
|
|
1094
|
+
/<\/?\s*style[^>]*>/gi,
|
|
1095
|
+
/<\/?\s*script[^>]*>/gi,
|
|
1096
|
+
/<!--[\s\S]*?-->/g,
|
|
1097
|
+
/@import\s+[^;]*;?/gi,
|
|
1098
|
+
/expression\s*\(/gi,
|
|
1099
|
+
/behavior\s*:/gi,
|
|
1100
|
+
/-moz-binding\s*:/gi,
|
|
1101
|
+
/javascript\s*:/gi,
|
|
1102
|
+
/vbscript\s*:/gi
|
|
1103
|
+
];
|
|
1104
|
+
var SDK_URL_DATA_RE = /url\s*\(\s*(['"]?)\s*data\s*:[^)]*\)/gi;
|
|
1105
|
+
function sanitizeBrandCss(input) {
|
|
1106
|
+
if (!input) return "";
|
|
1107
|
+
let out = String(input);
|
|
1108
|
+
if (out.length > SDK_CSS_MAX_LEN) out = out.slice(0, SDK_CSS_MAX_LEN);
|
|
1109
|
+
out = out.replace(/</g, "");
|
|
1110
|
+
for (const re of SDK_CSS_FORBIDDEN) out = out.replace(re, "");
|
|
1111
|
+
out = out.replace(SDK_URL_DATA_RE, "url()");
|
|
1112
|
+
return out;
|
|
1113
|
+
}
|
|
1114
|
+
function SdkBrandLogo({ branding, alt, fallback }) {
|
|
1115
|
+
const light = branding?.logoLightUrl || branding?.logoUrl || null;
|
|
1116
|
+
const dark = branding?.logoDarkUrl || null;
|
|
1117
|
+
if (!light && !dark) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
|
|
1118
|
+
const fallbackSrc = light || dark;
|
|
1119
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("picture", { "data-iqauth-sdk-logo": "", children: [
|
|
1120
|
+
dark ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("source", { srcSet: dark, media: "(prefers-color-scheme: dark)" }) : null,
|
|
1121
|
+
light ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("source", { srcSet: light, media: "(prefers-color-scheme: light)" }) : null,
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: fallbackSrc, alt })
|
|
1123
|
+
] });
|
|
1124
|
+
}
|
|
1125
|
+
var sdkBrandingCache = /* @__PURE__ */ new Map();
|
|
1126
|
+
var SDK_BRANDING_TTL_MS = 6e4;
|
|
1127
|
+
function flattenBrandingPayload(data) {
|
|
1128
|
+
const e = data && data.effective || {};
|
|
1129
|
+
const meta = data && data.meta || {};
|
|
1130
|
+
return {
|
|
1131
|
+
brandName: e.brandName ?? data?.brandName ?? null,
|
|
1132
|
+
logoUrl: e.logoLightUrl ?? data?.logoUrl ?? null,
|
|
1133
|
+
logoLightUrl: e.logoLightUrl ?? data?.logoLightUrl ?? null,
|
|
1134
|
+
logoDarkUrl: e.logoDarkUrl ?? data?.logoDarkUrl ?? null,
|
|
1135
|
+
faviconUrl: e.faviconUrl ?? data?.faviconUrl ?? null,
|
|
1136
|
+
primaryColor: e.primaryColor ?? data?.primaryColor ?? null,
|
|
1137
|
+
accentColor: e.accentColor ?? data?.accentColor ?? null,
|
|
1138
|
+
backgroundColor: e.backgroundColor ?? data?.backgroundColor ?? null,
|
|
1139
|
+
surfaceColor: e.surfaceColor ?? data?.surfaceColor ?? null,
|
|
1140
|
+
textColor: e.textColor ?? data?.textColor ?? null,
|
|
1141
|
+
fontFamilyBody: e.fontFamilyBody ?? data?.fontFamilyBody ?? null,
|
|
1142
|
+
fontFamilyHeading: e.fontFamilyHeading ?? data?.fontFamilyHeading ?? null,
|
|
1143
|
+
customFontUrl: e.customFontUrl ?? data?.customFontUrl ?? null,
|
|
1144
|
+
borderRadius: e.borderRadius ?? data?.borderRadius ?? null,
|
|
1145
|
+
backgroundImageUrl: e.backgroundImageUrl ?? data?.backgroundImageUrl ?? null,
|
|
1146
|
+
customCss: e.customCss ?? data?.customCss ?? null,
|
|
1147
|
+
loginLayout: e.loginLayout ?? data?.loginLayout ?? null,
|
|
1148
|
+
socialButtonStyle: e.socialButtonStyle ?? data?.socialButtonStyle ?? null,
|
|
1149
|
+
footerText: e.footerText ?? data?.footerText ?? null,
|
|
1150
|
+
brandingRev: meta.brandingRev ?? data?.brandingRev ?? null
|
|
1151
|
+
};
|
|
1152
|
+
}
|
|
1153
|
+
function useResolvedSdkBranding(iqAuthBaseUrl, appId) {
|
|
1154
|
+
const ctx = (0, import_react.useContext)(IQAuthContext);
|
|
1155
|
+
const resolvedAppId = appId ?? ctx?.manager?.appKey ?? null;
|
|
1156
|
+
const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/public/branding${resolvedAppId ? `?appId=${encodeURIComponent(resolvedAppId)}` : ""}`;
|
|
1157
|
+
const cached = sdkBrandingCache.get(url);
|
|
1158
|
+
const fresh = cached && Date.now() - cached.ts < SDK_BRANDING_TTL_MS ? cached.data : null;
|
|
1159
|
+
const [b, setB] = (0, import_react.useState)(fresh);
|
|
1160
|
+
(0, import_react.useEffect)(() => {
|
|
1161
|
+
let cancelled = false;
|
|
1162
|
+
const entry = sdkBrandingCache.get(url);
|
|
1163
|
+
const headers = {};
|
|
1164
|
+
if (entry?.rev) headers["If-None-Match"] = `W/"brand-${entry.rev}"`;
|
|
1165
|
+
if (entry) setB(entry.data);
|
|
1166
|
+
fetch(url, { credentials: "include", headers }).then(async (r) => {
|
|
1167
|
+
if (cancelled) return;
|
|
1168
|
+
if (r.status === 304 && entry) {
|
|
1169
|
+
sdkBrandingCache.set(url, { ...entry, ts: Date.now() });
|
|
1170
|
+
return;
|
|
1171
|
+
}
|
|
1172
|
+
if (!r.ok) return;
|
|
1173
|
+
const p = await r.json().catch(() => null);
|
|
1174
|
+
if (!p?.data) return;
|
|
1175
|
+
const flat = flattenBrandingPayload(p.data);
|
|
1176
|
+
sdkBrandingCache.set(url, { ts: Date.now(), rev: flat.brandingRev || "", data: flat });
|
|
1177
|
+
setB(flat);
|
|
1178
|
+
}).catch(() => {
|
|
1179
|
+
});
|
|
1180
|
+
return () => {
|
|
1181
|
+
cancelled = true;
|
|
1182
|
+
};
|
|
1183
|
+
}, [url]);
|
|
1184
|
+
return b;
|
|
1185
|
+
}
|
|
1020
1186
|
function ensureSdkShellStyles() {
|
|
1021
1187
|
if (typeof document === "undefined" || sdkShellStylesInjected) return;
|
|
1022
1188
|
const tag = document.createElement("style");
|
|
@@ -1062,35 +1228,61 @@ function Shell({
|
|
|
1062
1228
|
const brandVars = brandStyle(branding);
|
|
1063
1229
|
const brandName = branding?.brandName || "IQAuth";
|
|
1064
1230
|
const heroImage = branding?.heroImageUrl || null;
|
|
1231
|
+
const layout = (branding?.loginLayout || "split_screen").toString();
|
|
1232
|
+
const bgImage = branding?.backgroundImageUrl || null;
|
|
1233
|
+
const fontUrl = branding?.customFontUrl || null;
|
|
1234
|
+
const socialStyle = (branding?.socialButtonStyle || "").toString();
|
|
1065
1235
|
const heroStyle = heroImage ? { ["--iqauth-sdk-hero-image"]: `url("${heroImage.replace(/"/g, '\\"')}")` } : {};
|
|
1236
|
+
const shellStyle = {
|
|
1237
|
+
...brandVars,
|
|
1238
|
+
...layout === "full_bleed" && bgImage ? { backgroundImage: `linear-gradient(rgba(15,23,42,0.35), rgba(15,23,42,0.45)), url("${bgImage.replace(/"/g, '\\"')}")` } : {}
|
|
1239
|
+
};
|
|
1066
1240
|
const supportLink = branding?.supportUrl ? branding.supportUrl : branding?.supportEmail ? `mailto:${branding.supportEmail}` : null;
|
|
1067
1241
|
const hasFooterLinks = !!(branding?.termsUrl || branding?.privacyUrl || supportLink);
|
|
1068
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1243
|
+
"div",
|
|
1244
|
+
{
|
|
1245
|
+
className: `iqauth-sdk-shell${className ? ` ${className}` : ""}`,
|
|
1246
|
+
"data-layout": layout,
|
|
1247
|
+
"data-social-style": socialStyle || void 0,
|
|
1248
|
+
style: shellStyle,
|
|
1249
|
+
"data-iqauth-shell": "",
|
|
1250
|
+
"data-branding-rev": branding?.brandingRev || "",
|
|
1251
|
+
children: [
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { "data-brand": true, children: [
|
|
1253
|
+
fontUrl ? `@font-face{font-family:"${(branding?.fontFamilyBody || "Brand").replace(/"/g, "")}";src:url("${fontUrl.replace(/"/g, '\\"')}");font-display:swap;}` : "",
|
|
1254
|
+
sanitizeBrandCss(branding?.customCss)
|
|
1255
|
+
].filter(Boolean).join("\n") }),
|
|
1256
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", { className: "iqauth-sdk-hero", "data-bg-image": heroImage ? "true" : "false", style: heroStyle, "aria-hidden": "true", children: [
|
|
1257
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "iqauth-sdk-hero-brand", style: { display: "flex", alignItems: "center", gap: 12 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SdkBrandLogo, { branding, alt: "", fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "iqauth-sdk-hero-name", children: brandName }) }) }),
|
|
1258
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "iqauth-sdk-hero-content", children: [
|
|
1259
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: branding?.tagline || `Welcome to ${brandName}` }),
|
|
1260
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: branding?.loginSideCopy || branding?.loginSubheadline || `Sign in to continue to your ${brandName} workspace.` })
|
|
1261
|
+
] }),
|
|
1262
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "iqauth-sdk-hero-foot", children: `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brandName}` })
|
|
1263
|
+
] }),
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "iqauth-sdk-pane", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", { style: { width: "100%", maxWidth: 420 }, children: [
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "iqauth-sdk-mobile-brand", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SdkBrandLogo, { branding, alt: `${brandName} logo`, fallback: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: brandName }) }) }),
|
|
1266
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "iqauth-sdk-card", children: [
|
|
1267
|
+
title || subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "iqauth-sdk-card-header", children: [
|
|
1268
|
+
title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: title }) : null,
|
|
1269
|
+
subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: subtitle }) : null
|
|
1270
|
+
] }) : null,
|
|
1271
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "iqauth-sdk-card-body", children })
|
|
1272
|
+
] }),
|
|
1273
|
+
hasFooterLinks || branding?.footerText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", { className: "iqauth-sdk-footer", children: [
|
|
1274
|
+
branding?.footerText ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { "data-testid": "text-brand-footer-sdk", style: { fontSize: 12, opacity: 0.75 }, children: branding.footerText }) : null,
|
|
1275
|
+
hasFooterLinks ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "iqauth-sdk-footer-links", children: [
|
|
1276
|
+
branding?.termsUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: branding.termsUrl, target: "_blank", rel: "noreferrer noopener", children: "Terms" }) : null,
|
|
1277
|
+
branding?.privacyUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: branding.privacyUrl, target: "_blank", rel: "noreferrer noopener", children: "Privacy" }) : null,
|
|
1278
|
+
supportLink ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: supportLink, target: "_blank", rel: "noreferrer noopener", children: "Support" }) : null
|
|
1279
|
+
] }) : null
|
|
1280
|
+
] }) : null
|
|
1281
|
+
] }) })
|
|
1282
|
+
]
|
|
1283
|
+
},
|
|
1284
|
+
branding?.brandingRev || void 0
|
|
1285
|
+
);
|
|
1094
1286
|
}
|
|
1095
1287
|
function Field({ label, children }) {
|
|
1096
1288
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 13 }, children: [
|
|
@@ -1160,7 +1352,15 @@ function ErrorBanner({ message }) {
|
|
|
1160
1352
|
color: "#b91c1c"
|
|
1161
1353
|
}, children: message });
|
|
1162
1354
|
}
|
|
1163
|
-
function
|
|
1355
|
+
function isSilentSsoEligible(ctx, effectivePrompt) {
|
|
1356
|
+
if (!ctx) return false;
|
|
1357
|
+
if (effectivePrompt === "login") return false;
|
|
1358
|
+
if (!ctx.session) return false;
|
|
1359
|
+
if (!ctx.app.defaultClientId) return false;
|
|
1360
|
+
if (!ctx.returnAllowed) return false;
|
|
1361
|
+
return true;
|
|
1362
|
+
}
|
|
1363
|
+
function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className, prompt }) {
|
|
1164
1364
|
const { ctx, loading, error } = useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo);
|
|
1165
1365
|
const [email, setEmail] = (0, import_react.useState)("");
|
|
1166
1366
|
const [password, setPassword] = (0, import_react.useState)("");
|
|
@@ -1169,6 +1369,18 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
1169
1369
|
const [mfa, setMfa] = (0, import_react.useState)(null);
|
|
1170
1370
|
const [tenantSel, setTenantSel] = (0, import_react.useState)(null);
|
|
1171
1371
|
const [oauthExchanging, setOauthExchanging] = (0, import_react.useState)(false);
|
|
1372
|
+
const [silent, setSilent] = (0, import_react.useState)("idle");
|
|
1373
|
+
const [forcePrompt, setForcePrompt] = (0, import_react.useState)(false);
|
|
1374
|
+
const effectivePrompt = (0, import_react.useMemo)(() => {
|
|
1375
|
+
if (prompt === "login" || forcePrompt) return "login";
|
|
1376
|
+
if (typeof window !== "undefined") {
|
|
1377
|
+
try {
|
|
1378
|
+
if (new URLSearchParams(window.location.search).get("prompt") === "login") return "login";
|
|
1379
|
+
} catch {
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
return void 0;
|
|
1383
|
+
}, [prompt, forcePrompt]);
|
|
1172
1384
|
const oidcPayload = () => ({
|
|
1173
1385
|
client_id: ctx?.app.defaultClientId,
|
|
1174
1386
|
redirect_uri: returnTo,
|
|
@@ -1258,6 +1470,58 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
1258
1470
|
const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/google?redirect_uri=${encodeURIComponent(bridgeUrl)}&client_id=${encodeURIComponent(ctx.app.defaultClientId)}`;
|
|
1259
1471
|
window.location.href = url;
|
|
1260
1472
|
};
|
|
1473
|
+
(0, import_react.useEffect)(() => {
|
|
1474
|
+
if (loading || error || !ctx) return;
|
|
1475
|
+
if (effectivePrompt === "login") {
|
|
1476
|
+
setSilent("skipped");
|
|
1477
|
+
return;
|
|
1478
|
+
}
|
|
1479
|
+
if (silent !== "idle") return;
|
|
1480
|
+
if (!ctx.session || !ctx.app.defaultClientId || !ctx.returnAllowed) {
|
|
1481
|
+
setSilent("skipped");
|
|
1482
|
+
return;
|
|
1483
|
+
}
|
|
1484
|
+
setSilent("trying");
|
|
1485
|
+
(async () => {
|
|
1486
|
+
try {
|
|
1487
|
+
const r = await fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/oidc/sso-resume`, {
|
|
1488
|
+
method: "POST",
|
|
1489
|
+
headers: { "Content-Type": "application/json" },
|
|
1490
|
+
credentials: "include",
|
|
1491
|
+
body: JSON.stringify(oidcPayload())
|
|
1492
|
+
});
|
|
1493
|
+
const payload = await r.json().catch(() => ({}));
|
|
1494
|
+
if (payload?.type === "redirect" && payload.redirectUrl) {
|
|
1495
|
+
(onRedirect || ((u) => {
|
|
1496
|
+
window.location.replace(u);
|
|
1497
|
+
}))(payload.redirectUrl);
|
|
1498
|
+
return;
|
|
1499
|
+
}
|
|
1500
|
+
if (payload?.type === "tenant_selection") {
|
|
1501
|
+
setTenantSel({ token: payload.tenantSelectionToken, tenants: payload.tenants || [] });
|
|
1502
|
+
setSilent("failed");
|
|
1503
|
+
return;
|
|
1504
|
+
}
|
|
1505
|
+
setSilent("failed");
|
|
1506
|
+
} catch {
|
|
1507
|
+
setSilent("failed");
|
|
1508
|
+
}
|
|
1509
|
+
})();
|
|
1510
|
+
}, [loading, error, ctx, effectivePrompt]);
|
|
1511
|
+
const switchAccount = (e) => {
|
|
1512
|
+
if (e) e.preventDefault();
|
|
1513
|
+
setForcePrompt(true);
|
|
1514
|
+
setSilent("skipped");
|
|
1515
|
+
setTenantSel(null);
|
|
1516
|
+
if (typeof window !== "undefined") {
|
|
1517
|
+
try {
|
|
1518
|
+
const u = new URL(window.location.href);
|
|
1519
|
+
u.searchParams.set("prompt", "login");
|
|
1520
|
+
window.history.replaceState({}, "", u.toString());
|
|
1521
|
+
} catch {
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
};
|
|
1261
1525
|
(0, import_react.useEffect)(() => {
|
|
1262
1526
|
if (!ctx?.app.defaultClientId) return;
|
|
1263
1527
|
const params = new URLSearchParams(window.location.search);
|
|
@@ -1295,6 +1559,13 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
1295
1559
|
if (loading || oauthExchanging) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding: ctx?.branding || null, className, title: oauthExchanging ? "Completing sign-in\u2026" : "Loading\u2026", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: oauthExchanging ? "Completing sign-in\u2026" : "Loading\u2026" }) });
|
|
1296
1560
|
if (error || !ctx) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding: null, className, title: "Application unavailable", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, { message: error || "Failed to load app context" }) });
|
|
1297
1561
|
if (!ctx.returnAllowed) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding: ctx.branding, className, title: "Invalid redirect", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, { message: `returnTo "${returnTo}" is not in this app's allowed origins.` }) });
|
|
1562
|
+
const silentEligible = isSilentSsoEligible(ctx, effectivePrompt);
|
|
1563
|
+
if (silentEligible && silent !== "failed") {
|
|
1564
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding: ctx.branding, className, title: "Signing you in\u2026", subtitle: ctx.session ? `Welcome back, ${ctx.session.name || ctx.session.email}.` : void 0, children: [
|
|
1565
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { "data-testid": "text-silent-resume", style: { fontSize: 14, opacity: 0.8 }, children: "Resuming your session." }),
|
|
1566
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: "#", onClick: switchAccount, "data-testid": "link-switch-account", style: { fontSize: 13 }, children: "Not you? Use a different account" })
|
|
1567
|
+
] });
|
|
1568
|
+
}
|
|
1298
1569
|
const cardTitle = ctx.branding?.loginHeadline || `Sign in to ${ctx.app.name}`;
|
|
1299
1570
|
const cardSubtitle = ctx.branding?.loginSubheadline || void 0;
|
|
1300
1571
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding: ctx.branding, className, title: cardTitle, subtitle: cardSubtitle, children: [
|
|
@@ -1344,7 +1615,11 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
1344
1615
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Password", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: inputStyle(), type: "password", autoComplete: "current-password", required: true, value: password, onChange: (e) => setPassword(e.target.value) }) }),
|
|
1345
1616
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(PrimaryButton, { type: "submit", disabled: submitting || !email || !password, children: submitting ? "Signing in\u2026" : "Sign in" })
|
|
1346
1617
|
] })
|
|
1347
|
-
] })
|
|
1618
|
+
] }),
|
|
1619
|
+
(silent === "failed" || effectivePrompt === "login" && ctx.session) && !mfa ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { marginTop: 12, fontSize: 13, opacity: 0.75 }, children: [
|
|
1620
|
+
silent === "failed" && ctx.session ? "Couldn't resume your session. " : null,
|
|
1621
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: "#", onClick: switchAccount, "data-testid": "link-switch-account", children: "Use a different account" })
|
|
1622
|
+
] }) : null
|
|
1348
1623
|
] });
|
|
1349
1624
|
}
|
|
1350
1625
|
function SignUp({ iqAuthBaseUrl, appKey, returnTo, onSuccess, className }) {
|
|
@@ -1395,6 +1670,9 @@ function initialsOf(name, email) {
|
|
|
1395
1670
|
function UserButton({ iqAuthBaseUrl, accountUrl, onSignOut, className }) {
|
|
1396
1671
|
const [user, setUser] = (0, import_react.useState)(null);
|
|
1397
1672
|
const [open, setOpen] = (0, import_react.useState)(false);
|
|
1673
|
+
const branding = useResolvedSdkBranding(iqAuthBaseUrl);
|
|
1674
|
+
const accent = branding?.accentColor || "#6366f1";
|
|
1675
|
+
const primary = branding?.primaryColor || "#0f172a";
|
|
1398
1676
|
(0, import_react.useEffect)(() => {
|
|
1399
1677
|
let cancelled = false;
|
|
1400
1678
|
fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/me`, { credentials: "include" }).then((r) => r.json()).then((p) => {
|
|
@@ -1415,59 +1693,69 @@ function UserButton({ iqAuthBaseUrl, accountUrl, onSignOut, className }) {
|
|
|
1415
1693
|
};
|
|
1416
1694
|
if (!user) return null;
|
|
1417
1695
|
const target = accountUrl || `${iqAuthBaseUrl.replace(/\/$/, "")}/account`;
|
|
1418
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1697
|
+
"div",
|
|
1698
|
+
{
|
|
1699
|
+
className,
|
|
1700
|
+
style: { position: "relative", display: "inline-block", ...brandStyle(branding) },
|
|
1701
|
+
"data-iqauth-sdk-userbutton": "",
|
|
1702
|
+
"data-branding-rev": branding?.brandingRev || "",
|
|
1703
|
+
children: [
|
|
1704
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1705
|
+
"button",
|
|
1706
|
+
{
|
|
1707
|
+
type: "button",
|
|
1708
|
+
"aria-haspopup": "menu",
|
|
1709
|
+
"aria-expanded": open,
|
|
1710
|
+
onClick: () => setOpen((o) => !o),
|
|
1711
|
+
style: {
|
|
1712
|
+
width: 32,
|
|
1713
|
+
height: 32,
|
|
1714
|
+
borderRadius: "50%",
|
|
1715
|
+
background: accent,
|
|
1716
|
+
color: "#fff",
|
|
1717
|
+
border: "none",
|
|
1718
|
+
cursor: "pointer",
|
|
1719
|
+
fontSize: 12,
|
|
1720
|
+
fontWeight: 600
|
|
1721
|
+
},
|
|
1722
|
+
children: user.picture ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: user.picture, alt: user.name, style: { width: "100%", height: "100%", borderRadius: "50%" } }) : initialsOf(user.name, user.email)
|
|
1723
|
+
}
|
|
1724
|
+
),
|
|
1725
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "menu", style: {
|
|
1726
|
+
position: "absolute",
|
|
1727
|
+
right: 0,
|
|
1728
|
+
top: 40,
|
|
1729
|
+
minWidth: 200,
|
|
1730
|
+
background: "#fff",
|
|
1731
|
+
border: "1px solid rgba(15,23,42,0.12)",
|
|
1732
|
+
borderRadius: 8,
|
|
1733
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
|
|
1734
|
+
padding: 8,
|
|
1735
|
+
zIndex: 100
|
|
1736
|
+
}, children: [
|
|
1737
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "8px 10px", fontSize: 12, opacity: 0.7, borderBottom: "1px solid rgba(15,23,42,0.06)" }, children: [
|
|
1738
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontWeight: 500, color: "#0f172a" }, children: user.name }),
|
|
1739
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: user.email })
|
|
1740
|
+
] }),
|
|
1741
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: target, role: "menuitem", style: { display: "block", padding: "8px 10px", fontSize: 13, color: primary, textDecoration: "none" }, children: "Account" }),
|
|
1742
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1743
|
+
"button",
|
|
1744
|
+
{
|
|
1745
|
+
role: "menuitem",
|
|
1746
|
+
type: "button",
|
|
1747
|
+
onClick: signOut2,
|
|
1748
|
+
style: { display: "block", width: "100%", textAlign: "left", padding: "8px 10px", fontSize: 13, background: "transparent", border: "none", cursor: "pointer", color: "#b91c1c" },
|
|
1749
|
+
children: "Sign out"
|
|
1750
|
+
}
|
|
1751
|
+
)
|
|
1752
|
+
] }) : null
|
|
1753
|
+
]
|
|
1754
|
+
}
|
|
1755
|
+
);
|
|
1469
1756
|
}
|
|
1470
1757
|
function UserProfile({ iqAuthBaseUrl, className }) {
|
|
1758
|
+
const branding = useResolvedSdkBranding(iqAuthBaseUrl);
|
|
1471
1759
|
const [user, setUser] = (0, import_react.useState)(null);
|
|
1472
1760
|
const [oldPassword, setOldPassword] = (0, import_react.useState)("");
|
|
1473
1761
|
const [newPassword, setNewPassword] = (0, import_react.useState)("");
|
|
@@ -1501,8 +1789,8 @@ function UserProfile({ iqAuthBaseUrl, className }) {
|
|
|
1501
1789
|
await fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/sessions/${sessionId}`, { method: "DELETE", credentials: "include" });
|
|
1502
1790
|
setSessions((prev) => prev.filter((s) => s.id !== sessionId));
|
|
1503
1791
|
};
|
|
1504
|
-
if (!user) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding
|
|
1505
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding
|
|
1792
|
+
if (!user) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Loading account\u2026" }) });
|
|
1793
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding, className, children: [
|
|
1506
1794
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontSize: 20, fontWeight: 600, margin: "0 0 12px" }, children: "Your account" }),
|
|
1507
1795
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { "aria-labelledby": "iqauth-profile", style: { marginBottom: 20 }, children: [
|
|
1508
1796
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { id: "iqauth-profile", style: { fontSize: 14, fontWeight: 600 }, children: "Profile" }),
|
|
@@ -1537,6 +1825,8 @@ function UserProfile({ iqAuthBaseUrl, className }) {
|
|
|
1537
1825
|
] });
|
|
1538
1826
|
}
|
|
1539
1827
|
function OrganizationSwitcher({ iqAuthBaseUrl, onSwitched, className }) {
|
|
1828
|
+
const branding = useResolvedSdkBranding(iqAuthBaseUrl);
|
|
1829
|
+
const accent = branding?.accentColor || "#6366f1";
|
|
1540
1830
|
const [memberships, setMemberships] = (0, import_react.useState)([]);
|
|
1541
1831
|
const [activeTenantId, setActiveTenantId] = (0, import_react.useState)(null);
|
|
1542
1832
|
const [open, setOpen] = (0, import_react.useState)(false);
|
|
@@ -1562,60 +1852,71 @@ function OrganizationSwitcher({ iqAuthBaseUrl, onSwitched, className }) {
|
|
|
1562
1852
|
}
|
|
1563
1853
|
};
|
|
1564
1854
|
const active = memberships.find((m) => m.tenantId === activeTenantId);
|
|
1565
|
-
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1855
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1856
|
+
"div",
|
|
1857
|
+
{
|
|
1858
|
+
className,
|
|
1859
|
+
style: { position: "relative", display: "inline-block", ...brandStyle(branding) },
|
|
1860
|
+
"data-iqauth-sdk-orgswitcher": "",
|
|
1861
|
+
"data-branding-rev": branding?.brandingRev || "",
|
|
1862
|
+
children: [
|
|
1863
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1864
|
+
"button",
|
|
1865
|
+
{
|
|
1866
|
+
type: "button",
|
|
1867
|
+
"aria-haspopup": "menu",
|
|
1868
|
+
"aria-expanded": open,
|
|
1869
|
+
onClick: () => setOpen((o) => !o),
|
|
1870
|
+
style: { background: "transparent", border: `1px solid ${accent}55`, color: branding?.primaryColor || "#0f172a", padding: "6px 12px", borderRadius: 6, cursor: "pointer", fontSize: 13 },
|
|
1871
|
+
children: active?.tenantName || active?.tenantSlug || "Select organization"
|
|
1872
|
+
}
|
|
1873
|
+
),
|
|
1874
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { role: "menu", style: {
|
|
1875
|
+
position: "absolute",
|
|
1876
|
+
left: 0,
|
|
1877
|
+
top: 36,
|
|
1878
|
+
minWidth: 220,
|
|
1879
|
+
background: "#fff",
|
|
1880
|
+
border: "1px solid rgba(15,23,42,0.12)",
|
|
1881
|
+
borderRadius: 8,
|
|
1882
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
|
|
1883
|
+
padding: 8,
|
|
1884
|
+
zIndex: 100
|
|
1885
|
+
}, children: memberships.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { fontSize: 13, opacity: 0.6, padding: "4px 6px" }, children: "No memberships" }) : memberships.map((m) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1886
|
+
"button",
|
|
1887
|
+
{
|
|
1888
|
+
role: "menuitem",
|
|
1889
|
+
type: "button",
|
|
1890
|
+
onClick: () => switchTo(m.tenantId),
|
|
1891
|
+
style: {
|
|
1892
|
+
display: "block",
|
|
1893
|
+
width: "100%",
|
|
1894
|
+
textAlign: "left",
|
|
1895
|
+
padding: "8px 10px",
|
|
1896
|
+
background: m.tenantId === activeTenantId ? `${accent}14` : "transparent",
|
|
1897
|
+
border: "none",
|
|
1898
|
+
borderRadius: 4,
|
|
1899
|
+
cursor: "pointer",
|
|
1900
|
+
fontSize: 13,
|
|
1901
|
+
color: "#0f172a"
|
|
1902
|
+
},
|
|
1903
|
+
children: [
|
|
1904
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontWeight: 500 }, children: m.tenantName || m.tenantSlug || m.tenantId }),
|
|
1905
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 11, opacity: 0.6 }, children: m.roles.join(", ") })
|
|
1906
|
+
]
|
|
1907
|
+
},
|
|
1908
|
+
m.tenantId
|
|
1909
|
+
)) }) : null
|
|
1910
|
+
]
|
|
1911
|
+
}
|
|
1912
|
+
);
|
|
1614
1913
|
}
|
|
1615
1914
|
var __version__ = "phase-bc-1.0.0";
|
|
1616
1915
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1617
1916
|
0 && (module.exports = {
|
|
1618
1917
|
AuthCallback,
|
|
1918
|
+
IQAuthLoaded,
|
|
1919
|
+
IQAuthLoading,
|
|
1619
1920
|
IQAuthProvider,
|
|
1620
1921
|
OrganizationSwitcher,
|
|
1621
1922
|
RedirectToSignIn,
|
|
@@ -1626,10 +1927,13 @@ var __version__ = "phase-bc-1.0.0";
|
|
|
1626
1927
|
UserButton,
|
|
1627
1928
|
UserProfile,
|
|
1628
1929
|
__version__,
|
|
1930
|
+
isSilentSsoEligible,
|
|
1931
|
+
sanitizeBrandCss,
|
|
1629
1932
|
useAuth,
|
|
1630
1933
|
useAuthFetch,
|
|
1631
1934
|
useIQAuthSignInContext,
|
|
1632
1935
|
useOrganization,
|
|
1936
|
+
useResolvedSdkBranding,
|
|
1633
1937
|
useSession,
|
|
1634
1938
|
useUser
|
|
1635
1939
|
});
|