@iqauth/sdk 2.0.4 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/browser-session.d.mts +1 -1
  2. package/dist/browser-session.d.ts +1 -1
  3. package/dist/browser-session.js +4 -1
  4. package/dist/browser-session.mjs +1 -1
  5. package/dist/{chunk-JQWYIIIS.mjs → chunk-MDUHPQMM.mjs} +4 -1
  6. package/dist/{chunk-73R6BEGO.mjs → chunk-ZESHDJDU.mjs} +1 -1
  7. package/dist/{client-CggvJmmm.d.ts → client-DXbHb2ul.d.ts} +1 -1
  8. package/dist/{client-C1DXfB8Z.d.mts → client-Dv4v92Mj.d.mts} +1 -1
  9. package/dist/{express-BKAXB5Nl.d.ts → express-B4o3P8vK.d.ts} +1 -1
  10. package/dist/{express-CpfyYTmw.d.mts → express-BZmF1llh.d.mts} +1 -1
  11. package/dist/express.d.mts +3 -3
  12. package/dist/express.d.ts +3 -3
  13. package/dist/express.js +4 -1
  14. package/dist/express.mjs +2 -2
  15. package/dist/fastify.d.mts +6 -0
  16. package/dist/fastify.d.ts +6 -0
  17. package/dist/fastify.js +21 -3
  18. package/dist/fastify.mjs +18 -3
  19. package/dist/hono.js +4 -1
  20. package/dist/hono.mjs +1 -1
  21. package/dist/index.d.mts +2 -2
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.js +4 -1
  24. package/dist/index.mjs +2 -2
  25. package/dist/mobile.d.mts +1 -1
  26. package/dist/mobile.d.ts +1 -1
  27. package/dist/mobile.js +4 -1
  28. package/dist/mobile.mjs +1 -1
  29. package/dist/next.js +4 -1
  30. package/dist/next.mjs +1 -1
  31. package/dist/react.d.mts +64 -2
  32. package/dist/react.d.ts +64 -2
  33. package/dist/react.js +501 -132
  34. package/dist/react.mjs +498 -132
  35. package/dist/server.d.mts +2 -2
  36. package/dist/server.d.ts +2 -2
  37. package/dist/server.js +4 -1
  38. package/dist/server.mjs +2 -2
  39. package/dist/service.d.mts +1 -1
  40. package/dist/service.d.ts +1 -1
  41. package/dist/service.js +4 -1
  42. package/dist/service.mjs +1 -1
  43. package/package.json +1 -1
package/dist/react.js CHANGED
@@ -31,10 +31,13 @@ __export(react_exports, {
31
31
  UserButton: () => UserButton,
32
32
  UserProfile: () => UserProfile,
33
33
  __version__: () => __version__,
34
+ isSilentSsoEligible: () => isSilentSsoEligible,
35
+ sanitizeBrandCss: () => sanitizeBrandCss,
34
36
  useAuth: () => useAuth,
35
37
  useAuthFetch: () => useAuthFetch,
36
38
  useIQAuthSignInContext: () => useIQAuthSignInContext,
37
39
  useOrganization: () => useOrganization,
40
+ useResolvedSdkBranding: () => useResolvedSdkBranding,
38
41
  useSession: () => useSession,
39
42
  useUser: () => useUser
40
43
  });
@@ -911,6 +914,12 @@ function brandStyle(branding) {
911
914
  if (branding.backgroundColor) s["--brand-bg"] = branding.backgroundColor;
912
915
  if (branding.surfaceColor) s["--brand-surface"] = branding.surfaceColor;
913
916
  if (branding.textColor) s["--brand-text"] = branding.textColor;
917
+ if (branding.borderRadius != null && branding.borderRadius !== "") {
918
+ const n = typeof branding.borderRadius === "number" ? `${branding.borderRadius}px` : String(branding.borderRadius);
919
+ s["--brand-radius"] = n;
920
+ }
921
+ if (branding.fontFamilyBody) s["--brand-font-body"] = branding.fontFamilyBody;
922
+ if (branding.fontFamilyHeading) s["--brand-font-heading"] = branding.fontFamilyHeading;
914
923
  return s;
915
924
  }
916
925
  async function jsonFetch(url, init) {
@@ -935,7 +944,7 @@ function useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo) {
935
944
  let cancelled = false;
936
945
  setLoading(true);
937
946
  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) => {
947
+ fetch(url, { credentials: "include" }).then((r) => r.json()).then((payload) => {
939
948
  if (cancelled) return;
940
949
  if (payload?.success === false) throw new Error(payload?.error?.message || "Failed to load sign-in context");
941
950
  setCtx(payload.data);
@@ -950,28 +959,282 @@ function useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo) {
950
959
  }, [iqAuthBaseUrl, appKey, returnTo]);
951
960
  return { ctx, loading, error };
952
961
  }
962
+ var SHELL_CSS = `
963
+ .iqauth-sdk-shell {
964
+ min-height: 100vh;
965
+ width: 100%;
966
+ display: grid;
967
+ grid-template-columns: 1fr;
968
+ background: var(--brand-bg, #f7f7f6);
969
+ color: var(--brand-text, #0f172a);
970
+ }
971
+ .iqauth-sdk-hero { display: none; }
972
+ .iqauth-sdk-pane {
973
+ display: flex; flex-direction: column; align-items: center; justify-content: center;
974
+ padding: 48px 24px; min-height: 100vh;
975
+ }
976
+ .iqauth-sdk-card {
977
+ width: 100%; max-width: 460px;
978
+ background: var(--brand-surface, #ffffff);
979
+ border: 1px solid rgba(15,23,42,0.08);
980
+ border-radius: var(--brand-radius, 16px);
981
+ box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 12px 32px rgba(15,23,42,0.06);
982
+ overflow: hidden;
983
+ }
984
+ .iqauth-sdk-shell, .iqauth-sdk-shell input, .iqauth-sdk-shell button { font-family: var(--brand-font-body, inherit); }
985
+ .iqauth-sdk-shell h1, .iqauth-sdk-shell h2, .iqauth-sdk-shell h3 { font-family: var(--brand-font-heading, var(--brand-font-body, inherit)); }
986
+ .iqauth-sdk-shell[data-layout="centered_card"] { grid-template-columns: 1fr; }
987
+ .iqauth-sdk-shell[data-layout="centered_card"] .iqauth-sdk-hero { display: none; }
988
+ .iqauth-sdk-shell[data-layout="full_bleed"] { background-size: cover; background-position: center; background-repeat: no-repeat; }
989
+ .iqauth-sdk-shell[data-layout="full_bleed"] .iqauth-sdk-hero { display: none; }
990
+ .iqauth-sdk-shell[data-layout="full_bleed"] .iqauth-sdk-pane { background: rgba(15,23,42,0.30); }
991
+ .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); }
992
+ .iqauth-sdk-shell[data-social-style="ghost"] .iqauth-sdk-google-btn { background: transparent; border-color: transparent; color: var(--brand-text, inherit); }
993
+ .iqauth-sdk-shell[data-social-style="solid"] .iqauth-sdk-google-btn { background: var(--brand-primary, #3b82f6); border-color: transparent; color: #fff; }
994
+ .iqauth-sdk-shell[data-social-style="solid"] .iqauth-sdk-google-btn:hover { background: var(--brand-primary, #3b82f6); opacity: 0.92; }
995
+ .iqauth-sdk-card-header { padding: 32px 36px 0; }
996
+ .iqauth-sdk-card-header h1 { font-size: 24px; font-weight: 600; margin: 0; line-height: 1.2; letter-spacing: -0.01em; }
997
+ .iqauth-sdk-card-header p { margin: 8px 0 0; font-size: 14px; color: rgba(15,23,42,0.65); line-height: 1.5; }
998
+ .iqauth-sdk-card-body { padding: 32px 36px 28px; display: flex; flex-direction: column; gap: 18px; }
999
+ .iqauth-sdk-mobile-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; }
1000
+ .iqauth-sdk-mobile-brand img { height: 36px; width: auto; }
1001
+ .iqauth-sdk-mobile-brand span { font-size: 16px; font-weight: 600; }
1002
+ .iqauth-sdk-footer { margin-top: 20px; text-align: center; font-size: 13px; color: rgba(15,23,42,0.55); display: flex; flex-direction: column; gap: 8px; align-items: center; }
1003
+ .iqauth-sdk-footer-links { display: flex; gap: 14px; flex-wrap: wrap; justify-content: center; }
1004
+ .iqauth-sdk-footer-links a { color: inherit; opacity: 0.75; text-decoration: none; }
1005
+ .iqauth-sdk-footer-links a:hover { opacity: 1; text-decoration: underline; }
1006
+ .iqauth-sdk-divider { display: flex; align-items: center; gap: 10px; font-size: 12px; color: rgba(15,23,42,0.45); text-transform: uppercase; letter-spacing: 0.08em; }
1007
+ .iqauth-sdk-divider::before, .iqauth-sdk-divider::after { content: ""; flex: 1; height: 1px; background: rgba(15,23,42,0.1); }
1008
+ .iqauth-sdk-google-btn {
1009
+ display: inline-flex; align-items: center; justify-content: center; gap: 10px;
1010
+ width: 100%; padding: 10px 16px; border-radius: 8px;
1011
+ background: #fff; color: #0f172a;
1012
+ border: 1px solid rgba(15,23,42,0.18);
1013
+ font-size: 14px; font-weight: 500; cursor: pointer;
1014
+ transition: background 120ms ease, border-color 120ms ease;
1015
+ }
1016
+ .iqauth-sdk-google-btn:hover { background: #f8fafc; border-color: rgba(15,23,42,0.28); }
1017
+ .iqauth-sdk-google-btn[disabled] { opacity: 0.6; cursor: not-allowed; }
1018
+
1019
+ @media (min-width: 768px) {
1020
+ .iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
1021
+ .iqauth-sdk-hero {
1022
+ display: flex; flex-direction: column; justify-content: space-between;
1023
+ padding: clamp(32px, 4vw, 56px); color: #ffffff;
1024
+ background: linear-gradient(135deg, var(--brand-primary, #3b82f6) 0%, var(--brand-accent, #6366f1) 100%);
1025
+ background-size: cover; background-position: center;
1026
+ position: relative; overflow: hidden; min-height: 100vh;
1027
+ }
1028
+ .iqauth-sdk-hero[data-bg-image="true"] {
1029
+ background-image: var(--iqauth-sdk-hero-image), linear-gradient(135deg, var(--brand-primary, #3b82f6), var(--brand-accent, #6366f1));
1030
+ background-blend-mode: multiply;
1031
+ }
1032
+ .iqauth-sdk-hero-brand img { height: 40px; width: auto; filter: brightness(0) invert(1); opacity: 0.96; }
1033
+ .iqauth-sdk-hero-brand .iqauth-sdk-hero-name { font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
1034
+ .iqauth-sdk-hero-content { max-width: 520px; }
1035
+ .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; }
1036
+ .iqauth-sdk-hero-content p { font-size: 15px; line-height: 1.6; opacity: 0.92; margin: 0; white-space: pre-wrap; }
1037
+ .iqauth-sdk-hero-foot { font-size: 12px; opacity: 0.7; }
1038
+ .iqauth-sdk-mobile-brand { display: none; }
1039
+ }
1040
+ @media (min-width: 1280px) {
1041
+ .iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
1042
+ }
1043
+ `;
1044
+ var sdkShellStylesInjected = false;
1045
+ var SDK_CSS_MAX_LEN = 50 * 1024;
1046
+ var SDK_CSS_FORBIDDEN = [
1047
+ /<\/?\s*style[^>]*>/gi,
1048
+ /<\/?\s*script[^>]*>/gi,
1049
+ /<!--[\s\S]*?-->/g,
1050
+ /@import\s+[^;]*;?/gi,
1051
+ /expression\s*\(/gi,
1052
+ /behavior\s*:/gi,
1053
+ /-moz-binding\s*:/gi,
1054
+ /javascript\s*:/gi,
1055
+ /vbscript\s*:/gi
1056
+ ];
1057
+ var SDK_URL_DATA_RE = /url\s*\(\s*(['"]?)\s*data\s*:[^)]*\)/gi;
1058
+ function sanitizeBrandCss(input) {
1059
+ if (!input) return "";
1060
+ let out = String(input);
1061
+ if (out.length > SDK_CSS_MAX_LEN) out = out.slice(0, SDK_CSS_MAX_LEN);
1062
+ out = out.replace(/</g, "");
1063
+ for (const re of SDK_CSS_FORBIDDEN) out = out.replace(re, "");
1064
+ out = out.replace(SDK_URL_DATA_RE, "url()");
1065
+ return out;
1066
+ }
1067
+ function SdkBrandLogo({ branding, alt, fallback }) {
1068
+ const light = branding?.logoLightUrl || branding?.logoUrl || null;
1069
+ const dark = branding?.logoDarkUrl || null;
1070
+ if (!light && !dark) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: fallback });
1071
+ const fallbackSrc = light || dark;
1072
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("picture", { "data-iqauth-sdk-logo": "", children: [
1073
+ dark ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("source", { srcSet: dark, media: "(prefers-color-scheme: dark)" }) : null,
1074
+ light ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("source", { srcSet: light, media: "(prefers-color-scheme: light)" }) : null,
1075
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: fallbackSrc, alt })
1076
+ ] });
1077
+ }
1078
+ var sdkBrandingCache = /* @__PURE__ */ new Map();
1079
+ var SDK_BRANDING_TTL_MS = 6e4;
1080
+ function flattenBrandingPayload(data) {
1081
+ const e = data && data.effective || {};
1082
+ const meta = data && data.meta || {};
1083
+ return {
1084
+ brandName: e.brandName ?? data?.brandName ?? null,
1085
+ logoUrl: e.logoLightUrl ?? data?.logoUrl ?? null,
1086
+ logoLightUrl: e.logoLightUrl ?? data?.logoLightUrl ?? null,
1087
+ logoDarkUrl: e.logoDarkUrl ?? data?.logoDarkUrl ?? null,
1088
+ faviconUrl: e.faviconUrl ?? data?.faviconUrl ?? null,
1089
+ primaryColor: e.primaryColor ?? data?.primaryColor ?? null,
1090
+ accentColor: e.accentColor ?? data?.accentColor ?? null,
1091
+ backgroundColor: e.backgroundColor ?? data?.backgroundColor ?? null,
1092
+ surfaceColor: e.surfaceColor ?? data?.surfaceColor ?? null,
1093
+ textColor: e.textColor ?? data?.textColor ?? null,
1094
+ fontFamilyBody: e.fontFamilyBody ?? data?.fontFamilyBody ?? null,
1095
+ fontFamilyHeading: e.fontFamilyHeading ?? data?.fontFamilyHeading ?? null,
1096
+ customFontUrl: e.customFontUrl ?? data?.customFontUrl ?? null,
1097
+ borderRadius: e.borderRadius ?? data?.borderRadius ?? null,
1098
+ backgroundImageUrl: e.backgroundImageUrl ?? data?.backgroundImageUrl ?? null,
1099
+ customCss: e.customCss ?? data?.customCss ?? null,
1100
+ loginLayout: e.loginLayout ?? data?.loginLayout ?? null,
1101
+ socialButtonStyle: e.socialButtonStyle ?? data?.socialButtonStyle ?? null,
1102
+ footerText: e.footerText ?? data?.footerText ?? null,
1103
+ brandingRev: meta.brandingRev ?? data?.brandingRev ?? null
1104
+ };
1105
+ }
1106
+ function useResolvedSdkBranding(iqAuthBaseUrl, appId) {
1107
+ const ctx = (0, import_react.useContext)(IQAuthContext);
1108
+ const resolvedAppId = appId ?? ctx?.manager?.appKey ?? null;
1109
+ const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/public/branding${resolvedAppId ? `?appId=${encodeURIComponent(resolvedAppId)}` : ""}`;
1110
+ const cached = sdkBrandingCache.get(url);
1111
+ const fresh = cached && Date.now() - cached.ts < SDK_BRANDING_TTL_MS ? cached.data : null;
1112
+ const [b, setB] = (0, import_react.useState)(fresh);
1113
+ (0, import_react.useEffect)(() => {
1114
+ let cancelled = false;
1115
+ const entry = sdkBrandingCache.get(url);
1116
+ const headers = {};
1117
+ if (entry?.rev) headers["If-None-Match"] = `W/"brand-${entry.rev}"`;
1118
+ if (entry) setB(entry.data);
1119
+ fetch(url, { credentials: "include", headers }).then(async (r) => {
1120
+ if (cancelled) return;
1121
+ if (r.status === 304 && entry) {
1122
+ sdkBrandingCache.set(url, { ...entry, ts: Date.now() });
1123
+ return;
1124
+ }
1125
+ if (!r.ok) return;
1126
+ const p = await r.json().catch(() => null);
1127
+ if (!p?.data) return;
1128
+ const flat = flattenBrandingPayload(p.data);
1129
+ sdkBrandingCache.set(url, { ts: Date.now(), rev: flat.brandingRev || "", data: flat });
1130
+ setB(flat);
1131
+ }).catch(() => {
1132
+ });
1133
+ return () => {
1134
+ cancelled = true;
1135
+ };
1136
+ }, [url]);
1137
+ return b;
1138
+ }
1139
+ function ensureSdkShellStyles() {
1140
+ if (typeof document === "undefined" || sdkShellStylesInjected) return;
1141
+ const tag = document.createElement("style");
1142
+ tag.setAttribute("data-iqauth-sdk-shell", "");
1143
+ tag.textContent = SHELL_CSS;
1144
+ document.head.appendChild(tag);
1145
+ sdkShellStylesInjected = true;
1146
+ }
1147
+ function useDocumentBranding(branding, fallbackTitle) {
1148
+ (0, import_react.useEffect)(() => {
1149
+ if (typeof document === "undefined") return;
1150
+ const prevTitle = document.title;
1151
+ const brandName = branding?.brandName || "IQAuth";
1152
+ document.title = `${fallbackTitle} \xB7 ${brandName}`;
1153
+ let linkEl = null;
1154
+ let prevHref = null;
1155
+ if (branding?.faviconUrl) {
1156
+ linkEl = document.querySelector("link[rel='icon']");
1157
+ if (!linkEl) {
1158
+ linkEl = document.createElement("link");
1159
+ linkEl.rel = "icon";
1160
+ document.head.appendChild(linkEl);
1161
+ } else {
1162
+ prevHref = linkEl.href;
1163
+ }
1164
+ linkEl.href = branding.faviconUrl;
1165
+ }
1166
+ return () => {
1167
+ document.title = prevTitle;
1168
+ if (linkEl && prevHref !== null) linkEl.href = prevHref;
1169
+ };
1170
+ }, [branding?.brandName, branding?.faviconUrl, fallbackTitle]);
1171
+ }
953
1172
  function Shell({
954
1173
  branding,
955
1174
  className,
956
- children
1175
+ children,
1176
+ title,
1177
+ subtitle
957
1178
  }) {
1179
+ ensureSdkShellStyles();
1180
+ useDocumentBranding(branding, title || "Sign in");
1181
+ const brandVars = brandStyle(branding);
1182
+ const brandName = branding?.brandName || "IQAuth";
1183
+ const heroImage = branding?.heroImageUrl || null;
1184
+ const layout = (branding?.loginLayout || "split_screen").toString();
1185
+ const bgImage = branding?.backgroundImageUrl || null;
1186
+ const fontUrl = branding?.customFontUrl || null;
1187
+ const socialStyle = (branding?.socialButtonStyle || "").toString();
1188
+ const heroStyle = heroImage ? { ["--iqauth-sdk-hero-image"]: `url("${heroImage.replace(/"/g, '\\"')}")` } : {};
1189
+ const shellStyle = {
1190
+ ...brandVars,
1191
+ ...layout === "full_bleed" && bgImage ? { backgroundImage: `linear-gradient(rgba(15,23,42,0.35), rgba(15,23,42,0.45)), url("${bgImage.replace(/"/g, '\\"')}")` } : {}
1192
+ };
1193
+ const supportLink = branding?.supportUrl ? branding.supportUrl : branding?.supportEmail ? `mailto:${branding.supportEmail}` : null;
1194
+ const hasFooterLinks = !!(branding?.termsUrl || branding?.privacyUrl || supportLink);
958
1195
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
959
1196
  "div",
960
1197
  {
961
- className,
962
- style: {
963
- background: "var(--brand-surface, #ffffff)",
964
- color: "var(--brand-text, #0f172a)",
965
- border: "1px solid rgba(15,23,42,0.08)",
966
- borderRadius: 12,
967
- padding: 24,
968
- ...brandStyle(branding)
969
- },
1198
+ className: `iqauth-sdk-shell${className ? ` ${className}` : ""}`,
1199
+ "data-layout": layout,
1200
+ "data-social-style": socialStyle || void 0,
1201
+ style: shellStyle,
1202
+ "data-iqauth-shell": "",
1203
+ "data-branding-rev": branding?.brandingRev || "",
970
1204
  children: [
971
- branding?.logoUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("img", { src: branding.logoUrl, alt: branding.brandName || "", style: { height: 28, width: "auto", marginBottom: 16 } }) : null,
972
- children
1205
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { "data-brand": true, children: [
1206
+ fontUrl ? `@font-face{font-family:"${(branding?.fontFamilyBody || "Brand").replace(/"/g, "")}";src:url("${fontUrl.replace(/"/g, '\\"')}");font-display:swap;}` : "",
1207
+ sanitizeBrandCss(branding?.customCss)
1208
+ ].filter(Boolean).join("\n") }),
1209
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("aside", { className: "iqauth-sdk-hero", "data-bg-image": heroImage ? "true" : "false", style: heroStyle, "aria-hidden": "true", children: [
1210
+ /* @__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 }) }) }),
1211
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "iqauth-sdk-hero-content", children: [
1212
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { children: branding?.tagline || `Welcome to ${brandName}` }),
1213
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: branding?.loginSideCopy || branding?.loginSubheadline || `Sign in to continue to your ${brandName} workspace.` })
1214
+ ] }),
1215
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "iqauth-sdk-hero-foot", children: `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brandName}` })
1216
+ ] }),
1217
+ /* @__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: [
1218
+ /* @__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 }) }) }),
1219
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { className: "iqauth-sdk-card", children: [
1220
+ title || subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "iqauth-sdk-card-header", children: [
1221
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { children: title }) : null,
1222
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: subtitle }) : null
1223
+ ] }) : null,
1224
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "iqauth-sdk-card-body", children })
1225
+ ] }),
1226
+ hasFooterLinks || branding?.footerText ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("footer", { className: "iqauth-sdk-footer", children: [
1227
+ 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,
1228
+ hasFooterLinks ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "iqauth-sdk-footer-links", children: [
1229
+ branding?.termsUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: branding.termsUrl, target: "_blank", rel: "noreferrer noopener", children: "Terms" }) : null,
1230
+ branding?.privacyUrl ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: branding.privacyUrl, target: "_blank", rel: "noreferrer noopener", children: "Privacy" }) : null,
1231
+ supportLink ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: supportLink, target: "_blank", rel: "noreferrer noopener", children: "Support" }) : null
1232
+ ] }) : null
1233
+ ] }) : null
1234
+ ] }) })
973
1235
  ]
974
- }
1236
+ },
1237
+ branding?.brandingRev || void 0
975
1238
  );
976
1239
  }
977
1240
  function Field({ label, children }) {
@@ -1042,7 +1305,15 @@ function ErrorBanner({ message }) {
1042
1305
  color: "#b91c1c"
1043
1306
  }, children: message });
1044
1307
  }
1045
- function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
1308
+ function isSilentSsoEligible(ctx, effectivePrompt) {
1309
+ if (!ctx) return false;
1310
+ if (effectivePrompt === "login") return false;
1311
+ if (!ctx.session) return false;
1312
+ if (!ctx.app.defaultClientId) return false;
1313
+ if (!ctx.returnAllowed) return false;
1314
+ return true;
1315
+ }
1316
+ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className, prompt }) {
1046
1317
  const { ctx, loading, error } = useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo);
1047
1318
  const [email, setEmail] = (0, import_react.useState)("");
1048
1319
  const [password, setPassword] = (0, import_react.useState)("");
@@ -1051,6 +1322,18 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
1051
1322
  const [mfa, setMfa] = (0, import_react.useState)(null);
1052
1323
  const [tenantSel, setTenantSel] = (0, import_react.useState)(null);
1053
1324
  const [oauthExchanging, setOauthExchanging] = (0, import_react.useState)(false);
1325
+ const [silent, setSilent] = (0, import_react.useState)("idle");
1326
+ const [forcePrompt, setForcePrompt] = (0, import_react.useState)(false);
1327
+ const effectivePrompt = (0, import_react.useMemo)(() => {
1328
+ if (prompt === "login" || forcePrompt) return "login";
1329
+ if (typeof window !== "undefined") {
1330
+ try {
1331
+ if (new URLSearchParams(window.location.search).get("prompt") === "login") return "login";
1332
+ } catch {
1333
+ }
1334
+ }
1335
+ return void 0;
1336
+ }, [prompt, forcePrompt]);
1054
1337
  const oidcPayload = () => ({
1055
1338
  client_id: ctx?.app.defaultClientId,
1056
1339
  redirect_uri: returnTo,
@@ -1140,6 +1423,58 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
1140
1423
  const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/google?redirect_uri=${encodeURIComponent(bridgeUrl)}&client_id=${encodeURIComponent(ctx.app.defaultClientId)}`;
1141
1424
  window.location.href = url;
1142
1425
  };
1426
+ (0, import_react.useEffect)(() => {
1427
+ if (loading || error || !ctx) return;
1428
+ if (effectivePrompt === "login") {
1429
+ setSilent("skipped");
1430
+ return;
1431
+ }
1432
+ if (silent !== "idle") return;
1433
+ if (!ctx.session || !ctx.app.defaultClientId || !ctx.returnAllowed) {
1434
+ setSilent("skipped");
1435
+ return;
1436
+ }
1437
+ setSilent("trying");
1438
+ (async () => {
1439
+ try {
1440
+ const r = await fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/oidc/sso-resume`, {
1441
+ method: "POST",
1442
+ headers: { "Content-Type": "application/json" },
1443
+ credentials: "include",
1444
+ body: JSON.stringify(oidcPayload())
1445
+ });
1446
+ const payload = await r.json().catch(() => ({}));
1447
+ if (payload?.type === "redirect" && payload.redirectUrl) {
1448
+ (onRedirect || ((u) => {
1449
+ window.location.replace(u);
1450
+ }))(payload.redirectUrl);
1451
+ return;
1452
+ }
1453
+ if (payload?.type === "tenant_selection") {
1454
+ setTenantSel({ token: payload.tenantSelectionToken, tenants: payload.tenants || [] });
1455
+ setSilent("failed");
1456
+ return;
1457
+ }
1458
+ setSilent("failed");
1459
+ } catch {
1460
+ setSilent("failed");
1461
+ }
1462
+ })();
1463
+ }, [loading, error, ctx, effectivePrompt]);
1464
+ const switchAccount = (e) => {
1465
+ if (e) e.preventDefault();
1466
+ setForcePrompt(true);
1467
+ setSilent("skipped");
1468
+ setTenantSel(null);
1469
+ if (typeof window !== "undefined") {
1470
+ try {
1471
+ const u = new URL(window.location.href);
1472
+ u.searchParams.set("prompt", "login");
1473
+ window.history.replaceState({}, "", u.toString());
1474
+ } catch {
1475
+ }
1476
+ }
1477
+ };
1143
1478
  (0, import_react.useEffect)(() => {
1144
1479
  if (!ctx?.app.defaultClientId) return;
1145
1480
  const params = new URLSearchParams(window.location.search);
@@ -1174,13 +1509,20 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
1174
1509
  setOauthExchanging(false);
1175
1510
  })();
1176
1511
  }, [ctx?.app.defaultClientId]);
1177
- if (loading || oauthExchanging) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding: ctx?.branding || null, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: oauthExchanging ? "Completing sign-in\u2026" : "Loading\u2026" }) });
1178
- if (error || !ctx) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding: null, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, { message: error || "Failed to load app context" }) });
1179
- if (!ctx.returnAllowed) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding: ctx.branding, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, { message: `returnTo "${returnTo}" is not in this app's allowed origins.` }) });
1180
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding: ctx.branding, className, children: [
1181
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontSize: 20, fontWeight: 600, margin: "0 0 12px" }, children: ctx.branding?.loginHeadline || `Sign in to ${ctx.app.name}` }),
1182
- ctx.branding?.loginSubheadline ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { style: { marginBottom: 16, fontSize: 13, opacity: 0.7 }, children: ctx.branding.loginSubheadline }) : null,
1183
- formError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginBottom: 12 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, { message: formError }) }) : null,
1512
+ 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" }) });
1513
+ 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" }) });
1514
+ 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.` }) });
1515
+ const silentEligible = isSilentSsoEligible(ctx, effectivePrompt);
1516
+ if (silentEligible && silent !== "failed") {
1517
+ 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: [
1518
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { "data-testid": "text-silent-resume", style: { fontSize: 14, opacity: 0.8 }, children: "Resuming your session." }),
1519
+ /* @__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" })
1520
+ ] });
1521
+ }
1522
+ const cardTitle = ctx.branding?.loginHeadline || `Sign in to ${ctx.app.name}`;
1523
+ const cardSubtitle = ctx.branding?.loginSubheadline || void 0;
1524
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding: ctx.branding, className, title: cardTitle, subtitle: cardSubtitle, children: [
1525
+ formError ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ErrorBanner, { message: formError }) : null,
1184
1526
  tenantSel ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { role: "radiogroup", "aria-label": "Choose tenant", style: { display: "flex", flexDirection: "column", gap: 8 }, children: tenantSel.tenants.map((t) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1185
1527
  "button",
1186
1528
  {
@@ -1210,27 +1552,27 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
1210
1552
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(GhostButton, { type: "button", onClick: () => setMfa({ ...mfa, backup: !mfa.backup, code: "" }), children: mfa.backup ? "Use verification code" : "Use backup code" })
1211
1553
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
1212
1554
  ctx.providers?.google ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
1213
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(GhostButton, { type: "button", onClick: startGoogleLogin, disabled: submitting, "aria-label": "Continue with Google", style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 10 }, children: [
1555
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("button", { type: "button", className: "iqauth-sdk-google-btn", onClick: startGoogleLogin, disabled: submitting, "aria-label": ctx.branding?.googleButtonLabel || "Continue with Google", children: [
1214
1556
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("svg", { width: "18", height: "18", viewBox: "0 0 18 18", "aria-hidden": "true", children: [
1215
1557
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "#4285F4", d: "M17.64 9.2c0-.64-.06-1.25-.17-1.84H9v3.48h4.84a4.14 4.14 0 0 1-1.8 2.71v2.26h2.92a8.78 8.78 0 0 0 2.68-6.61z" }),
1216
1558
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "#34A853", d: "M9 18c2.43 0 4.47-.81 5.96-2.18l-2.92-2.26a5.4 5.4 0 0 1-8.04-2.83H.96v2.33A9 9 0 0 0 9 18z" }),
1217
1559
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "#FBBC05", d: "M3.96 10.71A5.41 5.41 0 0 1 3.68 9c0-.59.1-1.17.29-1.71V4.96H.96a9 9 0 0 0 0 8.08l3-2.33z" }),
1218
1560
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: "#EA4335", d: "M9 3.58c1.32 0 2.5.45 3.44 1.35l2.58-2.59A9 9 0 0 0 .96 4.96l3 2.33A5.4 5.4 0 0 1 9 3.58z" })
1219
1561
  ] }),
1220
- "Continue with Google"
1562
+ ctx.branding?.googleButtonLabel || "Continue with Google"
1221
1563
  ] }),
1222
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "separator", "aria-label": "or", style: { display: "flex", alignItems: "center", gap: 10, fontSize: 12, opacity: 0.6 }, children: [
1223
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(15,23,42,0.12)" } }),
1224
- "OR",
1225
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1, height: 1, background: "rgba(15,23,42,0.12)" } })
1226
- ] })
1564
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { role: "separator", "aria-label": "or", className: "iqauth-sdk-divider", children: "OR" })
1227
1565
  ] }) : null,
1228
1566
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", { onSubmit: submitLogin, style: { display: "flex", flexDirection: "column", gap: 12 }, "aria-label": `Sign in to ${ctx.app.name}`, children: [
1229
1567
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Field, { label: "Email", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", { style: inputStyle(), type: "email", autoComplete: "email", required: true, value: email, onChange: (e) => setEmail(e.target.value) }) }),
1230
1568
  /* @__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) }) }),
1231
1569
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PrimaryButton, { type: "submit", disabled: submitting || !email || !password, children: submitting ? "Signing in\u2026" : "Sign in" })
1232
1570
  ] })
1233
- ] })
1571
+ ] }),
1572
+ (silent === "failed" || effectivePrompt === "login" && ctx.session) && !mfa ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { style: { marginTop: 12, fontSize: 13, opacity: 0.75 }, children: [
1573
+ silent === "failed" && ctx.session ? "Couldn't resume your session. " : null,
1574
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: "#", onClick: switchAccount, "data-testid": "link-switch-account", children: "Use a different account" })
1575
+ ] }) : null
1234
1576
  ] });
1235
1577
  }
1236
1578
  function SignUp({ iqAuthBaseUrl, appKey, returnTo, onSuccess, className }) {
@@ -1281,6 +1623,9 @@ function initialsOf(name, email) {
1281
1623
  function UserButton({ iqAuthBaseUrl, accountUrl, onSignOut, className }) {
1282
1624
  const [user, setUser] = (0, import_react.useState)(null);
1283
1625
  const [open, setOpen] = (0, import_react.useState)(false);
1626
+ const branding = useResolvedSdkBranding(iqAuthBaseUrl);
1627
+ const accent = branding?.accentColor || "#6366f1";
1628
+ const primary = branding?.primaryColor || "#0f172a";
1284
1629
  (0, import_react.useEffect)(() => {
1285
1630
  let cancelled = false;
1286
1631
  fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/me`, { credentials: "include" }).then((r) => r.json()).then((p) => {
@@ -1301,59 +1646,69 @@ function UserButton({ iqAuthBaseUrl, accountUrl, onSignOut, className }) {
1301
1646
  };
1302
1647
  if (!user) return null;
1303
1648
  const target = accountUrl || `${iqAuthBaseUrl.replace(/\/$/, "")}/account`;
1304
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, style: { position: "relative", display: "inline-block" }, children: [
1305
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1306
- "button",
1307
- {
1308
- type: "button",
1309
- "aria-haspopup": "menu",
1310
- "aria-expanded": open,
1311
- onClick: () => setOpen((o) => !o),
1312
- style: {
1313
- width: 32,
1314
- height: 32,
1315
- borderRadius: "50%",
1316
- background: "var(--brand-accent, #6366f1)",
1317
- color: "#fff",
1318
- border: "none",
1319
- cursor: "pointer",
1320
- fontSize: 12,
1321
- fontWeight: 600
1322
- },
1323
- 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)
1324
- }
1325
- ),
1326
- open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "menu", style: {
1327
- position: "absolute",
1328
- right: 0,
1329
- top: 40,
1330
- minWidth: 200,
1331
- background: "#fff",
1332
- border: "1px solid rgba(15,23,42,0.12)",
1333
- borderRadius: 8,
1334
- boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
1335
- padding: 8,
1336
- zIndex: 100
1337
- }, children: [
1338
- /* @__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: [
1339
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontWeight: 500, color: "#0f172a" }, children: user.name }),
1340
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: user.email })
1341
- ] }),
1342
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("a", { href: target, role: "menuitem", style: { display: "block", padding: "8px 10px", fontSize: 13, color: "#0f172a", textDecoration: "none" }, children: "Account" }),
1343
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1344
- "button",
1345
- {
1346
- role: "menuitem",
1347
- type: "button",
1348
- onClick: signOut2,
1349
- style: { display: "block", width: "100%", textAlign: "left", padding: "8px 10px", fontSize: 13, background: "transparent", border: "none", cursor: "pointer", color: "#b91c1c" },
1350
- children: "Sign out"
1351
- }
1352
- )
1353
- ] }) : null
1354
- ] });
1649
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1650
+ "div",
1651
+ {
1652
+ className,
1653
+ style: { position: "relative", display: "inline-block", ...brandStyle(branding) },
1654
+ "data-iqauth-sdk-userbutton": "",
1655
+ "data-branding-rev": branding?.brandingRev || "",
1656
+ children: [
1657
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1658
+ "button",
1659
+ {
1660
+ type: "button",
1661
+ "aria-haspopup": "menu",
1662
+ "aria-expanded": open,
1663
+ onClick: () => setOpen((o) => !o),
1664
+ style: {
1665
+ width: 32,
1666
+ height: 32,
1667
+ borderRadius: "50%",
1668
+ background: accent,
1669
+ color: "#fff",
1670
+ border: "none",
1671
+ cursor: "pointer",
1672
+ fontSize: 12,
1673
+ fontWeight: 600
1674
+ },
1675
+ 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)
1676
+ }
1677
+ ),
1678
+ open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { role: "menu", style: {
1679
+ position: "absolute",
1680
+ right: 0,
1681
+ top: 40,
1682
+ minWidth: 200,
1683
+ background: "#fff",
1684
+ border: "1px solid rgba(15,23,42,0.12)",
1685
+ borderRadius: 8,
1686
+ boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
1687
+ padding: 8,
1688
+ zIndex: 100
1689
+ }, children: [
1690
+ /* @__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: [
1691
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontWeight: 500, color: "#0f172a" }, children: user.name }),
1692
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { children: user.email })
1693
+ ] }),
1694
+ /* @__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" }),
1695
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1696
+ "button",
1697
+ {
1698
+ role: "menuitem",
1699
+ type: "button",
1700
+ onClick: signOut2,
1701
+ style: { display: "block", width: "100%", textAlign: "left", padding: "8px 10px", fontSize: 13, background: "transparent", border: "none", cursor: "pointer", color: "#b91c1c" },
1702
+ children: "Sign out"
1703
+ }
1704
+ )
1705
+ ] }) : null
1706
+ ]
1707
+ }
1708
+ );
1355
1709
  }
1356
1710
  function UserProfile({ iqAuthBaseUrl, className }) {
1711
+ const branding = useResolvedSdkBranding(iqAuthBaseUrl);
1357
1712
  const [user, setUser] = (0, import_react.useState)(null);
1358
1713
  const [oldPassword, setOldPassword] = (0, import_react.useState)("");
1359
1714
  const [newPassword, setNewPassword] = (0, import_react.useState)("");
@@ -1387,8 +1742,8 @@ function UserProfile({ iqAuthBaseUrl, className }) {
1387
1742
  await fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/sessions/${sessionId}`, { method: "DELETE", credentials: "include" });
1388
1743
  setSessions((prev) => prev.filter((s) => s.id !== sessionId));
1389
1744
  };
1390
- if (!user) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding: null, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Loading account\u2026" }) });
1391
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding: null, className, children: [
1745
+ if (!user) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Shell, { branding, className, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { children: "Loading account\u2026" }) });
1746
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(Shell, { branding, className, children: [
1392
1747
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h2", { style: { fontSize: 20, fontWeight: 600, margin: "0 0 12px" }, children: "Your account" }),
1393
1748
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { "aria-labelledby": "iqauth-profile", style: { marginBottom: 20 }, children: [
1394
1749
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h3", { id: "iqauth-profile", style: { fontSize: 14, fontWeight: 600 }, children: "Profile" }),
@@ -1423,6 +1778,8 @@ function UserProfile({ iqAuthBaseUrl, className }) {
1423
1778
  ] });
1424
1779
  }
1425
1780
  function OrganizationSwitcher({ iqAuthBaseUrl, onSwitched, className }) {
1781
+ const branding = useResolvedSdkBranding(iqAuthBaseUrl);
1782
+ const accent = branding?.accentColor || "#6366f1";
1426
1783
  const [memberships, setMemberships] = (0, import_react.useState)([]);
1427
1784
  const [activeTenantId, setActiveTenantId] = (0, import_react.useState)(null);
1428
1785
  const [open, setOpen] = (0, import_react.useState)(false);
@@ -1448,55 +1805,64 @@ function OrganizationSwitcher({ iqAuthBaseUrl, onSwitched, className }) {
1448
1805
  }
1449
1806
  };
1450
1807
  const active = memberships.find((m) => m.tenantId === activeTenantId);
1451
- return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className, style: { position: "relative", display: "inline-block" }, children: [
1452
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1453
- "button",
1454
- {
1455
- type: "button",
1456
- "aria-haspopup": "menu",
1457
- "aria-expanded": open,
1458
- onClick: () => setOpen((o) => !o),
1459
- style: { background: "transparent", border: "1px solid rgba(15,23,42,0.15)", padding: "6px 12px", borderRadius: 6, cursor: "pointer", fontSize: 13 },
1460
- children: active?.tenantName || active?.tenantSlug || "Select organization"
1461
- }
1462
- ),
1463
- open ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { role: "menu", style: {
1464
- position: "absolute",
1465
- left: 0,
1466
- top: 36,
1467
- minWidth: 220,
1468
- background: "#fff",
1469
- border: "1px solid rgba(15,23,42,0.12)",
1470
- borderRadius: 8,
1471
- boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
1472
- padding: 8,
1473
- zIndex: 100
1474
- }, 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)(
1475
- "button",
1476
- {
1477
- role: "menuitem",
1478
- type: "button",
1479
- onClick: () => switchTo(m.tenantId),
1480
- style: {
1481
- display: "block",
1482
- width: "100%",
1483
- textAlign: "left",
1484
- padding: "8px 10px",
1485
- background: m.tenantId === activeTenantId ? "rgba(99,102,241,0.08)" : "transparent",
1486
- border: "none",
1487
- borderRadius: 4,
1488
- cursor: "pointer",
1489
- fontSize: 13,
1490
- color: "#0f172a"
1491
- },
1492
- children: [
1493
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontWeight: 500 }, children: m.tenantName || m.tenantSlug || m.tenantId }),
1494
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 11, opacity: 0.6 }, children: m.roles.join(", ") })
1495
- ]
1496
- },
1497
- m.tenantId
1498
- )) }) : null
1499
- ] });
1808
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
1809
+ "div",
1810
+ {
1811
+ className,
1812
+ style: { position: "relative", display: "inline-block", ...brandStyle(branding) },
1813
+ "data-iqauth-sdk-orgswitcher": "",
1814
+ "data-branding-rev": branding?.brandingRev || "",
1815
+ children: [
1816
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
1817
+ "button",
1818
+ {
1819
+ type: "button",
1820
+ "aria-haspopup": "menu",
1821
+ "aria-expanded": open,
1822
+ onClick: () => setOpen((o) => !o),
1823
+ style: { background: "transparent", border: `1px solid ${accent}55`, color: branding?.primaryColor || "#0f172a", padding: "6px 12px", borderRadius: 6, cursor: "pointer", fontSize: 13 },
1824
+ children: active?.tenantName || active?.tenantSlug || "Select organization"
1825
+ }
1826
+ ),
1827
+ open ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { role: "menu", style: {
1828
+ position: "absolute",
1829
+ left: 0,
1830
+ top: 36,
1831
+ minWidth: 220,
1832
+ background: "#fff",
1833
+ border: "1px solid rgba(15,23,42,0.12)",
1834
+ borderRadius: 8,
1835
+ boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
1836
+ padding: 8,
1837
+ zIndex: 100
1838
+ }, 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)(
1839
+ "button",
1840
+ {
1841
+ role: "menuitem",
1842
+ type: "button",
1843
+ onClick: () => switchTo(m.tenantId),
1844
+ style: {
1845
+ display: "block",
1846
+ width: "100%",
1847
+ textAlign: "left",
1848
+ padding: "8px 10px",
1849
+ background: m.tenantId === activeTenantId ? `${accent}14` : "transparent",
1850
+ border: "none",
1851
+ borderRadius: 4,
1852
+ cursor: "pointer",
1853
+ fontSize: 13,
1854
+ color: "#0f172a"
1855
+ },
1856
+ children: [
1857
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontWeight: 500 }, children: m.tenantName || m.tenantSlug || m.tenantId }),
1858
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { fontSize: 11, opacity: 0.6 }, children: m.roles.join(", ") })
1859
+ ]
1860
+ },
1861
+ m.tenantId
1862
+ )) }) : null
1863
+ ]
1864
+ }
1865
+ );
1500
1866
  }
1501
1867
  var __version__ = "phase-bc-1.0.0";
1502
1868
  // Annotate the CommonJS export names for ESM import in node:
@@ -1512,10 +1878,13 @@ var __version__ = "phase-bc-1.0.0";
1512
1878
  UserButton,
1513
1879
  UserProfile,
1514
1880
  __version__,
1881
+ isSilentSsoEligible,
1882
+ sanitizeBrandCss,
1515
1883
  useAuth,
1516
1884
  useAuthFetch,
1517
1885
  useIQAuthSignInContext,
1518
1886
  useOrganization,
1887
+ useResolvedSdkBranding,
1519
1888
  useSession,
1520
1889
  useUser
1521
1890
  });