@iqauth/sdk 2.0.5 → 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.
- package/dist/react.d.mts +57 -2
- package/dist/react.d.ts +57 -2
- package/dist/react.js +400 -145
- package/dist/react.mjs +397 -145
- package/package.json +1 -1
package/dist/react.mjs
CHANGED
|
@@ -212,6 +212,12 @@ function brandStyle(branding) {
|
|
|
212
212
|
if (branding.backgroundColor) s["--brand-bg"] = branding.backgroundColor;
|
|
213
213
|
if (branding.surfaceColor) s["--brand-surface"] = branding.surfaceColor;
|
|
214
214
|
if (branding.textColor) s["--brand-text"] = branding.textColor;
|
|
215
|
+
if (branding.borderRadius != null && branding.borderRadius !== "") {
|
|
216
|
+
const n = typeof branding.borderRadius === "number" ? `${branding.borderRadius}px` : String(branding.borderRadius);
|
|
217
|
+
s["--brand-radius"] = n;
|
|
218
|
+
}
|
|
219
|
+
if (branding.fontFamilyBody) s["--brand-font-body"] = branding.fontFamilyBody;
|
|
220
|
+
if (branding.fontFamilyHeading) s["--brand-font-heading"] = branding.fontFamilyHeading;
|
|
215
221
|
return s;
|
|
216
222
|
}
|
|
217
223
|
async function jsonFetch(url, init) {
|
|
@@ -236,7 +242,7 @@ function useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo) {
|
|
|
236
242
|
let cancelled = false;
|
|
237
243
|
setLoading(true);
|
|
238
244
|
const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/public/apps/${encodeURIComponent(appKey)}/sign-in-context?return_to=${encodeURIComponent(returnTo)}`;
|
|
239
|
-
fetch(url).then((r) => r.json()).then((payload) => {
|
|
245
|
+
fetch(url, { credentials: "include" }).then((r) => r.json()).then((payload) => {
|
|
240
246
|
if (cancelled) return;
|
|
241
247
|
if (payload?.success === false) throw new Error(payload?.error?.message || "Failed to load sign-in context");
|
|
242
248
|
setCtx(payload.data);
|
|
@@ -254,6 +260,7 @@ function useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo) {
|
|
|
254
260
|
var SHELL_CSS = `
|
|
255
261
|
.iqauth-sdk-shell {
|
|
256
262
|
min-height: 100vh;
|
|
263
|
+
width: 100%;
|
|
257
264
|
display: grid;
|
|
258
265
|
grid-template-columns: 1fr;
|
|
259
266
|
background: var(--brand-bg, #f7f7f6);
|
|
@@ -262,20 +269,31 @@ var SHELL_CSS = `
|
|
|
262
269
|
.iqauth-sdk-hero { display: none; }
|
|
263
270
|
.iqauth-sdk-pane {
|
|
264
271
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
|
265
|
-
padding:
|
|
272
|
+
padding: 48px 24px; min-height: 100vh;
|
|
266
273
|
}
|
|
267
274
|
.iqauth-sdk-card {
|
|
268
|
-
width: 100%; max-width:
|
|
275
|
+
width: 100%; max-width: 460px;
|
|
269
276
|
background: var(--brand-surface, #ffffff);
|
|
270
277
|
border: 1px solid rgba(15,23,42,0.08);
|
|
271
|
-
border-radius:
|
|
272
|
-
box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0
|
|
278
|
+
border-radius: var(--brand-radius, 16px);
|
|
279
|
+
box-shadow: 0 1px 2px rgba(0,0,0,0.04), 0 12px 32px rgba(15,23,42,0.06);
|
|
273
280
|
overflow: hidden;
|
|
274
281
|
}
|
|
275
|
-
.iqauth-sdk-
|
|
276
|
-
.iqauth-sdk-
|
|
282
|
+
.iqauth-sdk-shell, .iqauth-sdk-shell input, .iqauth-sdk-shell button { font-family: var(--brand-font-body, inherit); }
|
|
283
|
+
.iqauth-sdk-shell h1, .iqauth-sdk-shell h2, .iqauth-sdk-shell h3 { font-family: var(--brand-font-heading, var(--brand-font-body, inherit)); }
|
|
284
|
+
.iqauth-sdk-shell[data-layout="centered_card"] { grid-template-columns: 1fr; }
|
|
285
|
+
.iqauth-sdk-shell[data-layout="centered_card"] .iqauth-sdk-hero { display: none; }
|
|
286
|
+
.iqauth-sdk-shell[data-layout="full_bleed"] { background-size: cover; background-position: center; background-repeat: no-repeat; }
|
|
287
|
+
.iqauth-sdk-shell[data-layout="full_bleed"] .iqauth-sdk-hero { display: none; }
|
|
288
|
+
.iqauth-sdk-shell[data-layout="full_bleed"] .iqauth-sdk-pane { background: rgba(15,23,42,0.30); }
|
|
289
|
+
.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); }
|
|
290
|
+
.iqauth-sdk-shell[data-social-style="ghost"] .iqauth-sdk-google-btn { background: transparent; border-color: transparent; color: var(--brand-text, inherit); }
|
|
291
|
+
.iqauth-sdk-shell[data-social-style="solid"] .iqauth-sdk-google-btn { background: var(--brand-primary, #3b82f6); border-color: transparent; color: #fff; }
|
|
292
|
+
.iqauth-sdk-shell[data-social-style="solid"] .iqauth-sdk-google-btn:hover { background: var(--brand-primary, #3b82f6); opacity: 0.92; }
|
|
293
|
+
.iqauth-sdk-card-header { padding: 32px 36px 0; }
|
|
294
|
+
.iqauth-sdk-card-header h1 { font-size: 24px; font-weight: 600; margin: 0; line-height: 1.2; letter-spacing: -0.01em; }
|
|
277
295
|
.iqauth-sdk-card-header p { margin: 8px 0 0; font-size: 14px; color: rgba(15,23,42,0.65); line-height: 1.5; }
|
|
278
|
-
.iqauth-sdk-card-body { padding:
|
|
296
|
+
.iqauth-sdk-card-body { padding: 32px 36px 28px; display: flex; flex-direction: column; gap: 18px; }
|
|
279
297
|
.iqauth-sdk-mobile-brand { display: flex; align-items: center; gap: 10px; margin-bottom: 20px; }
|
|
280
298
|
.iqauth-sdk-mobile-brand img { height: 36px; width: auto; }
|
|
281
299
|
.iqauth-sdk-mobile-brand span { font-size: 16px; font-weight: 600; }
|
|
@@ -296,11 +314,11 @@ var SHELL_CSS = `
|
|
|
296
314
|
.iqauth-sdk-google-btn:hover { background: #f8fafc; border-color: rgba(15,23,42,0.28); }
|
|
297
315
|
.iqauth-sdk-google-btn[disabled] { opacity: 0.6; cursor: not-allowed; }
|
|
298
316
|
|
|
299
|
-
@media (min-width:
|
|
300
|
-
.iqauth-sdk-shell { grid-template-columns: minmax(0,
|
|
317
|
+
@media (min-width: 768px) {
|
|
318
|
+
.iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
|
|
301
319
|
.iqauth-sdk-hero {
|
|
302
320
|
display: flex; flex-direction: column; justify-content: space-between;
|
|
303
|
-
padding:
|
|
321
|
+
padding: clamp(32px, 4vw, 56px); color: #ffffff;
|
|
304
322
|
background: linear-gradient(135deg, var(--brand-primary, #3b82f6) 0%, var(--brand-accent, #6366f1) 100%);
|
|
305
323
|
background-size: cover; background-position: center;
|
|
306
324
|
position: relative; overflow: hidden; min-height: 100vh;
|
|
@@ -309,15 +327,113 @@ var SHELL_CSS = `
|
|
|
309
327
|
background-image: var(--iqauth-sdk-hero-image), linear-gradient(135deg, var(--brand-primary, #3b82f6), var(--brand-accent, #6366f1));
|
|
310
328
|
background-blend-mode: multiply;
|
|
311
329
|
}
|
|
312
|
-
.iqauth-sdk-hero-brand img { height:
|
|
313
|
-
.iqauth-sdk-hero-brand .iqauth-sdk-hero-name { font-size:
|
|
314
|
-
.iqauth-sdk-hero-content
|
|
315
|
-
.iqauth-sdk-hero-content
|
|
330
|
+
.iqauth-sdk-hero-brand img { height: 40px; width: auto; filter: brightness(0) invert(1); opacity: 0.96; }
|
|
331
|
+
.iqauth-sdk-hero-brand .iqauth-sdk-hero-name { font-size: 20px; font-weight: 600; letter-spacing: -0.01em; }
|
|
332
|
+
.iqauth-sdk-hero-content { max-width: 520px; }
|
|
333
|
+
.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; }
|
|
334
|
+
.iqauth-sdk-hero-content p { font-size: 15px; line-height: 1.6; opacity: 0.92; margin: 0; white-space: pre-wrap; }
|
|
316
335
|
.iqauth-sdk-hero-foot { font-size: 12px; opacity: 0.7; }
|
|
317
336
|
.iqauth-sdk-mobile-brand { display: none; }
|
|
318
337
|
}
|
|
338
|
+
@media (min-width: 1280px) {
|
|
339
|
+
.iqauth-sdk-shell:not([data-layout="centered_card"]):not([data-layout="full_bleed"]) { grid-template-columns: minmax(0, 5fr) minmax(0, 6fr); }
|
|
340
|
+
}
|
|
319
341
|
`;
|
|
320
342
|
var sdkShellStylesInjected = false;
|
|
343
|
+
var SDK_CSS_MAX_LEN = 50 * 1024;
|
|
344
|
+
var SDK_CSS_FORBIDDEN = [
|
|
345
|
+
/<\/?\s*style[^>]*>/gi,
|
|
346
|
+
/<\/?\s*script[^>]*>/gi,
|
|
347
|
+
/<!--[\s\S]*?-->/g,
|
|
348
|
+
/@import\s+[^;]*;?/gi,
|
|
349
|
+
/expression\s*\(/gi,
|
|
350
|
+
/behavior\s*:/gi,
|
|
351
|
+
/-moz-binding\s*:/gi,
|
|
352
|
+
/javascript\s*:/gi,
|
|
353
|
+
/vbscript\s*:/gi
|
|
354
|
+
];
|
|
355
|
+
var SDK_URL_DATA_RE = /url\s*\(\s*(['"]?)\s*data\s*:[^)]*\)/gi;
|
|
356
|
+
function sanitizeBrandCss(input) {
|
|
357
|
+
if (!input) return "";
|
|
358
|
+
let out = String(input);
|
|
359
|
+
if (out.length > SDK_CSS_MAX_LEN) out = out.slice(0, SDK_CSS_MAX_LEN);
|
|
360
|
+
out = out.replace(/</g, "");
|
|
361
|
+
for (const re of SDK_CSS_FORBIDDEN) out = out.replace(re, "");
|
|
362
|
+
out = out.replace(SDK_URL_DATA_RE, "url()");
|
|
363
|
+
return out;
|
|
364
|
+
}
|
|
365
|
+
function SdkBrandLogo({ branding, alt, fallback }) {
|
|
366
|
+
const light = branding?.logoLightUrl || branding?.logoUrl || null;
|
|
367
|
+
const dark = branding?.logoDarkUrl || null;
|
|
368
|
+
if (!light && !dark) return /* @__PURE__ */ jsx(Fragment2, { children: fallback });
|
|
369
|
+
const fallbackSrc = light || dark;
|
|
370
|
+
return /* @__PURE__ */ jsxs("picture", { "data-iqauth-sdk-logo": "", children: [
|
|
371
|
+
dark ? /* @__PURE__ */ jsx("source", { srcSet: dark, media: "(prefers-color-scheme: dark)" }) : null,
|
|
372
|
+
light ? /* @__PURE__ */ jsx("source", { srcSet: light, media: "(prefers-color-scheme: light)" }) : null,
|
|
373
|
+
/* @__PURE__ */ jsx("img", { src: fallbackSrc, alt })
|
|
374
|
+
] });
|
|
375
|
+
}
|
|
376
|
+
var sdkBrandingCache = /* @__PURE__ */ new Map();
|
|
377
|
+
var SDK_BRANDING_TTL_MS = 6e4;
|
|
378
|
+
function flattenBrandingPayload(data) {
|
|
379
|
+
const e = data && data.effective || {};
|
|
380
|
+
const meta = data && data.meta || {};
|
|
381
|
+
return {
|
|
382
|
+
brandName: e.brandName ?? data?.brandName ?? null,
|
|
383
|
+
logoUrl: e.logoLightUrl ?? data?.logoUrl ?? null,
|
|
384
|
+
logoLightUrl: e.logoLightUrl ?? data?.logoLightUrl ?? null,
|
|
385
|
+
logoDarkUrl: e.logoDarkUrl ?? data?.logoDarkUrl ?? null,
|
|
386
|
+
faviconUrl: e.faviconUrl ?? data?.faviconUrl ?? null,
|
|
387
|
+
primaryColor: e.primaryColor ?? data?.primaryColor ?? null,
|
|
388
|
+
accentColor: e.accentColor ?? data?.accentColor ?? null,
|
|
389
|
+
backgroundColor: e.backgroundColor ?? data?.backgroundColor ?? null,
|
|
390
|
+
surfaceColor: e.surfaceColor ?? data?.surfaceColor ?? null,
|
|
391
|
+
textColor: e.textColor ?? data?.textColor ?? null,
|
|
392
|
+
fontFamilyBody: e.fontFamilyBody ?? data?.fontFamilyBody ?? null,
|
|
393
|
+
fontFamilyHeading: e.fontFamilyHeading ?? data?.fontFamilyHeading ?? null,
|
|
394
|
+
customFontUrl: e.customFontUrl ?? data?.customFontUrl ?? null,
|
|
395
|
+
borderRadius: e.borderRadius ?? data?.borderRadius ?? null,
|
|
396
|
+
backgroundImageUrl: e.backgroundImageUrl ?? data?.backgroundImageUrl ?? null,
|
|
397
|
+
customCss: e.customCss ?? data?.customCss ?? null,
|
|
398
|
+
loginLayout: e.loginLayout ?? data?.loginLayout ?? null,
|
|
399
|
+
socialButtonStyle: e.socialButtonStyle ?? data?.socialButtonStyle ?? null,
|
|
400
|
+
footerText: e.footerText ?? data?.footerText ?? null,
|
|
401
|
+
brandingRev: meta.brandingRev ?? data?.brandingRev ?? null
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
function useResolvedSdkBranding(iqAuthBaseUrl, appId) {
|
|
405
|
+
const ctx = useContext(IQAuthContext);
|
|
406
|
+
const resolvedAppId = appId ?? ctx?.manager?.appKey ?? null;
|
|
407
|
+
const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/public/branding${resolvedAppId ? `?appId=${encodeURIComponent(resolvedAppId)}` : ""}`;
|
|
408
|
+
const cached = sdkBrandingCache.get(url);
|
|
409
|
+
const fresh = cached && Date.now() - cached.ts < SDK_BRANDING_TTL_MS ? cached.data : null;
|
|
410
|
+
const [b, setB] = useState(fresh);
|
|
411
|
+
useEffect(() => {
|
|
412
|
+
let cancelled = false;
|
|
413
|
+
const entry = sdkBrandingCache.get(url);
|
|
414
|
+
const headers = {};
|
|
415
|
+
if (entry?.rev) headers["If-None-Match"] = `W/"brand-${entry.rev}"`;
|
|
416
|
+
if (entry) setB(entry.data);
|
|
417
|
+
fetch(url, { credentials: "include", headers }).then(async (r) => {
|
|
418
|
+
if (cancelled) return;
|
|
419
|
+
if (r.status === 304 && entry) {
|
|
420
|
+
sdkBrandingCache.set(url, { ...entry, ts: Date.now() });
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (!r.ok) return;
|
|
424
|
+
const p = await r.json().catch(() => null);
|
|
425
|
+
if (!p?.data) return;
|
|
426
|
+
const flat = flattenBrandingPayload(p.data);
|
|
427
|
+
sdkBrandingCache.set(url, { ts: Date.now(), rev: flat.brandingRev || "", data: flat });
|
|
428
|
+
setB(flat);
|
|
429
|
+
}).catch(() => {
|
|
430
|
+
});
|
|
431
|
+
return () => {
|
|
432
|
+
cancelled = true;
|
|
433
|
+
};
|
|
434
|
+
}, [url]);
|
|
435
|
+
return b;
|
|
436
|
+
}
|
|
321
437
|
function ensureSdkShellStyles() {
|
|
322
438
|
if (typeof document === "undefined" || sdkShellStylesInjected) return;
|
|
323
439
|
const tag = document.createElement("style");
|
|
@@ -363,35 +479,61 @@ function Shell({
|
|
|
363
479
|
const brandVars = brandStyle(branding);
|
|
364
480
|
const brandName = branding?.brandName || "IQAuth";
|
|
365
481
|
const heroImage = branding?.heroImageUrl || null;
|
|
482
|
+
const layout = (branding?.loginLayout || "split_screen").toString();
|
|
483
|
+
const bgImage = branding?.backgroundImageUrl || null;
|
|
484
|
+
const fontUrl = branding?.customFontUrl || null;
|
|
485
|
+
const socialStyle = (branding?.socialButtonStyle || "").toString();
|
|
366
486
|
const heroStyle = heroImage ? { ["--iqauth-sdk-hero-image"]: `url("${heroImage.replace(/"/g, '\\"')}")` } : {};
|
|
487
|
+
const shellStyle = {
|
|
488
|
+
...brandVars,
|
|
489
|
+
...layout === "full_bleed" && bgImage ? { backgroundImage: `linear-gradient(rgba(15,23,42,0.35), rgba(15,23,42,0.45)), url("${bgImage.replace(/"/g, '\\"')}")` } : {}
|
|
490
|
+
};
|
|
367
491
|
const supportLink = branding?.supportUrl ? branding.supportUrl : branding?.supportEmail ? `mailto:${branding.supportEmail}` : null;
|
|
368
492
|
const hasFooterLinks = !!(branding?.termsUrl || branding?.privacyUrl || supportLink);
|
|
369
|
-
return /* @__PURE__ */ jsxs(
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
493
|
+
return /* @__PURE__ */ jsxs(
|
|
494
|
+
"div",
|
|
495
|
+
{
|
|
496
|
+
className: `iqauth-sdk-shell${className ? ` ${className}` : ""}`,
|
|
497
|
+
"data-layout": layout,
|
|
498
|
+
"data-social-style": socialStyle || void 0,
|
|
499
|
+
style: shellStyle,
|
|
500
|
+
"data-iqauth-shell": "",
|
|
501
|
+
"data-branding-rev": branding?.brandingRev || "",
|
|
502
|
+
children: [
|
|
503
|
+
/* @__PURE__ */ jsx("style", { "data-brand": true, children: [
|
|
504
|
+
fontUrl ? `@font-face{font-family:"${(branding?.fontFamilyBody || "Brand").replace(/"/g, "")}";src:url("${fontUrl.replace(/"/g, '\\"')}");font-display:swap;}` : "",
|
|
505
|
+
sanitizeBrandCss(branding?.customCss)
|
|
506
|
+
].filter(Boolean).join("\n") }),
|
|
507
|
+
/* @__PURE__ */ jsxs("aside", { className: "iqauth-sdk-hero", "data-bg-image": heroImage ? "true" : "false", style: heroStyle, "aria-hidden": "true", children: [
|
|
508
|
+
/* @__PURE__ */ jsx("div", { className: "iqauth-sdk-hero-brand", style: { display: "flex", alignItems: "center", gap: 12 }, children: /* @__PURE__ */ jsx(SdkBrandLogo, { branding, alt: "", fallback: /* @__PURE__ */ jsx("span", { className: "iqauth-sdk-hero-name", children: brandName }) }) }),
|
|
509
|
+
/* @__PURE__ */ jsxs("div", { className: "iqauth-sdk-hero-content", children: [
|
|
510
|
+
/* @__PURE__ */ jsx("h2", { children: branding?.tagline || `Welcome to ${brandName}` }),
|
|
511
|
+
/* @__PURE__ */ jsx("p", { children: branding?.loginSideCopy || branding?.loginSubheadline || `Sign in to continue to your ${brandName} workspace.` })
|
|
512
|
+
] }),
|
|
513
|
+
/* @__PURE__ */ jsx("div", { className: "iqauth-sdk-hero-foot", children: `\xA9 ${(/* @__PURE__ */ new Date()).getFullYear()} ${brandName}` })
|
|
514
|
+
] }),
|
|
515
|
+
/* @__PURE__ */ jsx("div", { className: "iqauth-sdk-pane", children: /* @__PURE__ */ jsxs("main", { style: { width: "100%", maxWidth: 420 }, children: [
|
|
516
|
+
/* @__PURE__ */ jsx("div", { className: "iqauth-sdk-mobile-brand", children: /* @__PURE__ */ jsx(SdkBrandLogo, { branding, alt: `${brandName} logo`, fallback: /* @__PURE__ */ jsx("span", { children: brandName }) }) }),
|
|
517
|
+
/* @__PURE__ */ jsxs("section", { className: "iqauth-sdk-card", children: [
|
|
518
|
+
title || subtitle ? /* @__PURE__ */ jsxs("div", { className: "iqauth-sdk-card-header", children: [
|
|
519
|
+
title ? /* @__PURE__ */ jsx("h1", { children: title }) : null,
|
|
520
|
+
subtitle ? /* @__PURE__ */ jsx("p", { children: subtitle }) : null
|
|
521
|
+
] }) : null,
|
|
522
|
+
/* @__PURE__ */ jsx("div", { className: "iqauth-sdk-card-body", children })
|
|
523
|
+
] }),
|
|
524
|
+
hasFooterLinks || branding?.footerText ? /* @__PURE__ */ jsxs("footer", { className: "iqauth-sdk-footer", children: [
|
|
525
|
+
branding?.footerText ? /* @__PURE__ */ jsx("div", { "data-testid": "text-brand-footer-sdk", style: { fontSize: 12, opacity: 0.75 }, children: branding.footerText }) : null,
|
|
526
|
+
hasFooterLinks ? /* @__PURE__ */ jsxs("div", { className: "iqauth-sdk-footer-links", children: [
|
|
527
|
+
branding?.termsUrl ? /* @__PURE__ */ jsx("a", { href: branding.termsUrl, target: "_blank", rel: "noreferrer noopener", children: "Terms" }) : null,
|
|
528
|
+
branding?.privacyUrl ? /* @__PURE__ */ jsx("a", { href: branding.privacyUrl, target: "_blank", rel: "noreferrer noopener", children: "Privacy" }) : null,
|
|
529
|
+
supportLink ? /* @__PURE__ */ jsx("a", { href: supportLink, target: "_blank", rel: "noreferrer noopener", children: "Support" }) : null
|
|
530
|
+
] }) : null
|
|
531
|
+
] }) : null
|
|
532
|
+
] }) })
|
|
533
|
+
]
|
|
534
|
+
},
|
|
535
|
+
branding?.brandingRev || void 0
|
|
536
|
+
);
|
|
395
537
|
}
|
|
396
538
|
function Field({ label, children }) {
|
|
397
539
|
return /* @__PURE__ */ jsxs("label", { style: { display: "flex", flexDirection: "column", gap: 6, fontSize: 13 }, children: [
|
|
@@ -461,7 +603,15 @@ function ErrorBanner({ message }) {
|
|
|
461
603
|
color: "#b91c1c"
|
|
462
604
|
}, children: message });
|
|
463
605
|
}
|
|
464
|
-
function
|
|
606
|
+
function isSilentSsoEligible(ctx, effectivePrompt) {
|
|
607
|
+
if (!ctx) return false;
|
|
608
|
+
if (effectivePrompt === "login") return false;
|
|
609
|
+
if (!ctx.session) return false;
|
|
610
|
+
if (!ctx.app.defaultClientId) return false;
|
|
611
|
+
if (!ctx.returnAllowed) return false;
|
|
612
|
+
return true;
|
|
613
|
+
}
|
|
614
|
+
function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className, prompt }) {
|
|
465
615
|
const { ctx, loading, error } = useIQAuthSignInContext(iqAuthBaseUrl, appKey, returnTo);
|
|
466
616
|
const [email, setEmail] = useState("");
|
|
467
617
|
const [password, setPassword] = useState("");
|
|
@@ -470,6 +620,18 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
470
620
|
const [mfa, setMfa] = useState(null);
|
|
471
621
|
const [tenantSel, setTenantSel] = useState(null);
|
|
472
622
|
const [oauthExchanging, setOauthExchanging] = useState(false);
|
|
623
|
+
const [silent, setSilent] = useState("idle");
|
|
624
|
+
const [forcePrompt, setForcePrompt] = useState(false);
|
|
625
|
+
const effectivePrompt = useMemo(() => {
|
|
626
|
+
if (prompt === "login" || forcePrompt) return "login";
|
|
627
|
+
if (typeof window !== "undefined") {
|
|
628
|
+
try {
|
|
629
|
+
if (new URLSearchParams(window.location.search).get("prompt") === "login") return "login";
|
|
630
|
+
} catch {
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
return void 0;
|
|
634
|
+
}, [prompt, forcePrompt]);
|
|
473
635
|
const oidcPayload = () => ({
|
|
474
636
|
client_id: ctx?.app.defaultClientId,
|
|
475
637
|
redirect_uri: returnTo,
|
|
@@ -559,6 +721,58 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
559
721
|
const url = `${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/google?redirect_uri=${encodeURIComponent(bridgeUrl)}&client_id=${encodeURIComponent(ctx.app.defaultClientId)}`;
|
|
560
722
|
window.location.href = url;
|
|
561
723
|
};
|
|
724
|
+
useEffect(() => {
|
|
725
|
+
if (loading || error || !ctx) return;
|
|
726
|
+
if (effectivePrompt === "login") {
|
|
727
|
+
setSilent("skipped");
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
if (silent !== "idle") return;
|
|
731
|
+
if (!ctx.session || !ctx.app.defaultClientId || !ctx.returnAllowed) {
|
|
732
|
+
setSilent("skipped");
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
setSilent("trying");
|
|
736
|
+
(async () => {
|
|
737
|
+
try {
|
|
738
|
+
const r = await fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/oidc/sso-resume`, {
|
|
739
|
+
method: "POST",
|
|
740
|
+
headers: { "Content-Type": "application/json" },
|
|
741
|
+
credentials: "include",
|
|
742
|
+
body: JSON.stringify(oidcPayload())
|
|
743
|
+
});
|
|
744
|
+
const payload = await r.json().catch(() => ({}));
|
|
745
|
+
if (payload?.type === "redirect" && payload.redirectUrl) {
|
|
746
|
+
(onRedirect || ((u) => {
|
|
747
|
+
window.location.replace(u);
|
|
748
|
+
}))(payload.redirectUrl);
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (payload?.type === "tenant_selection") {
|
|
752
|
+
setTenantSel({ token: payload.tenantSelectionToken, tenants: payload.tenants || [] });
|
|
753
|
+
setSilent("failed");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
setSilent("failed");
|
|
757
|
+
} catch {
|
|
758
|
+
setSilent("failed");
|
|
759
|
+
}
|
|
760
|
+
})();
|
|
761
|
+
}, [loading, error, ctx, effectivePrompt]);
|
|
762
|
+
const switchAccount = (e) => {
|
|
763
|
+
if (e) e.preventDefault();
|
|
764
|
+
setForcePrompt(true);
|
|
765
|
+
setSilent("skipped");
|
|
766
|
+
setTenantSel(null);
|
|
767
|
+
if (typeof window !== "undefined") {
|
|
768
|
+
try {
|
|
769
|
+
const u = new URL(window.location.href);
|
|
770
|
+
u.searchParams.set("prompt", "login");
|
|
771
|
+
window.history.replaceState({}, "", u.toString());
|
|
772
|
+
} catch {
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
};
|
|
562
776
|
useEffect(() => {
|
|
563
777
|
if (!ctx?.app.defaultClientId) return;
|
|
564
778
|
const params = new URLSearchParams(window.location.search);
|
|
@@ -596,6 +810,13 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
596
810
|
if (loading || oauthExchanging) return /* @__PURE__ */ jsx(Shell, { branding: ctx?.branding || null, className, title: oauthExchanging ? "Completing sign-in\u2026" : "Loading\u2026", children: /* @__PURE__ */ jsx("p", { children: oauthExchanging ? "Completing sign-in\u2026" : "Loading\u2026" }) });
|
|
597
811
|
if (error || !ctx) return /* @__PURE__ */ jsx(Shell, { branding: null, className, title: "Application unavailable", children: /* @__PURE__ */ jsx(ErrorBanner, { message: error || "Failed to load app context" }) });
|
|
598
812
|
if (!ctx.returnAllowed) return /* @__PURE__ */ jsx(Shell, { branding: ctx.branding, className, title: "Invalid redirect", children: /* @__PURE__ */ jsx(ErrorBanner, { message: `returnTo "${returnTo}" is not in this app's allowed origins.` }) });
|
|
813
|
+
const silentEligible = isSilentSsoEligible(ctx, effectivePrompt);
|
|
814
|
+
if (silentEligible && silent !== "failed") {
|
|
815
|
+
return /* @__PURE__ */ 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: [
|
|
816
|
+
/* @__PURE__ */ jsx("p", { "data-testid": "text-silent-resume", style: { fontSize: 14, opacity: 0.8 }, children: "Resuming your session." }),
|
|
817
|
+
/* @__PURE__ */ jsx("a", { href: "#", onClick: switchAccount, "data-testid": "link-switch-account", style: { fontSize: 13 }, children: "Not you? Use a different account" })
|
|
818
|
+
] });
|
|
819
|
+
}
|
|
599
820
|
const cardTitle = ctx.branding?.loginHeadline || `Sign in to ${ctx.app.name}`;
|
|
600
821
|
const cardSubtitle = ctx.branding?.loginSubheadline || void 0;
|
|
601
822
|
return /* @__PURE__ */ jsxs(Shell, { branding: ctx.branding, className, title: cardTitle, subtitle: cardSubtitle, children: [
|
|
@@ -645,7 +866,11 @@ function SignIn({ iqAuthBaseUrl, appKey, returnTo, onRedirect, className }) {
|
|
|
645
866
|
/* @__PURE__ */ jsx(Field, { label: "Password", children: /* @__PURE__ */ jsx("input", { style: inputStyle(), type: "password", autoComplete: "current-password", required: true, value: password, onChange: (e) => setPassword(e.target.value) }) }),
|
|
646
867
|
/* @__PURE__ */ jsx(PrimaryButton, { type: "submit", disabled: submitting || !email || !password, children: submitting ? "Signing in\u2026" : "Sign in" })
|
|
647
868
|
] })
|
|
648
|
-
] })
|
|
869
|
+
] }),
|
|
870
|
+
(silent === "failed" || effectivePrompt === "login" && ctx.session) && !mfa ? /* @__PURE__ */ jsxs("p", { style: { marginTop: 12, fontSize: 13, opacity: 0.75 }, children: [
|
|
871
|
+
silent === "failed" && ctx.session ? "Couldn't resume your session. " : null,
|
|
872
|
+
/* @__PURE__ */ jsx("a", { href: "#", onClick: switchAccount, "data-testid": "link-switch-account", children: "Use a different account" })
|
|
873
|
+
] }) : null
|
|
649
874
|
] });
|
|
650
875
|
}
|
|
651
876
|
function SignUp({ iqAuthBaseUrl, appKey, returnTo, onSuccess, className }) {
|
|
@@ -696,6 +921,9 @@ function initialsOf(name, email) {
|
|
|
696
921
|
function UserButton({ iqAuthBaseUrl, accountUrl, onSignOut, className }) {
|
|
697
922
|
const [user, setUser] = useState(null);
|
|
698
923
|
const [open, setOpen] = useState(false);
|
|
924
|
+
const branding = useResolvedSdkBranding(iqAuthBaseUrl);
|
|
925
|
+
const accent = branding?.accentColor || "#6366f1";
|
|
926
|
+
const primary = branding?.primaryColor || "#0f172a";
|
|
699
927
|
useEffect(() => {
|
|
700
928
|
let cancelled = false;
|
|
701
929
|
fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/me`, { credentials: "include" }).then((r) => r.json()).then((p) => {
|
|
@@ -716,59 +944,69 @@ function UserButton({ iqAuthBaseUrl, accountUrl, onSignOut, className }) {
|
|
|
716
944
|
};
|
|
717
945
|
if (!user) return null;
|
|
718
946
|
const target = accountUrl || `${iqAuthBaseUrl.replace(/\/$/, "")}/account`;
|
|
719
|
-
return /* @__PURE__ */ jsxs(
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
947
|
+
return /* @__PURE__ */ jsxs(
|
|
948
|
+
"div",
|
|
949
|
+
{
|
|
950
|
+
className,
|
|
951
|
+
style: { position: "relative", display: "inline-block", ...brandStyle(branding) },
|
|
952
|
+
"data-iqauth-sdk-userbutton": "",
|
|
953
|
+
"data-branding-rev": branding?.brandingRev || "",
|
|
954
|
+
children: [
|
|
955
|
+
/* @__PURE__ */ jsx(
|
|
956
|
+
"button",
|
|
957
|
+
{
|
|
958
|
+
type: "button",
|
|
959
|
+
"aria-haspopup": "menu",
|
|
960
|
+
"aria-expanded": open,
|
|
961
|
+
onClick: () => setOpen((o) => !o),
|
|
962
|
+
style: {
|
|
963
|
+
width: 32,
|
|
964
|
+
height: 32,
|
|
965
|
+
borderRadius: "50%",
|
|
966
|
+
background: accent,
|
|
967
|
+
color: "#fff",
|
|
968
|
+
border: "none",
|
|
969
|
+
cursor: "pointer",
|
|
970
|
+
fontSize: 12,
|
|
971
|
+
fontWeight: 600
|
|
972
|
+
},
|
|
973
|
+
children: user.picture ? /* @__PURE__ */ jsx("img", { src: user.picture, alt: user.name, style: { width: "100%", height: "100%", borderRadius: "50%" } }) : initialsOf(user.name, user.email)
|
|
974
|
+
}
|
|
975
|
+
),
|
|
976
|
+
open ? /* @__PURE__ */ jsxs("div", { role: "menu", style: {
|
|
977
|
+
position: "absolute",
|
|
978
|
+
right: 0,
|
|
979
|
+
top: 40,
|
|
980
|
+
minWidth: 200,
|
|
981
|
+
background: "#fff",
|
|
982
|
+
border: "1px solid rgba(15,23,42,0.12)",
|
|
983
|
+
borderRadius: 8,
|
|
984
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
|
|
985
|
+
padding: 8,
|
|
986
|
+
zIndex: 100
|
|
987
|
+
}, children: [
|
|
988
|
+
/* @__PURE__ */ jsxs("div", { style: { padding: "8px 10px", fontSize: 12, opacity: 0.7, borderBottom: "1px solid rgba(15,23,42,0.06)" }, children: [
|
|
989
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 500, color: "#0f172a" }, children: user.name }),
|
|
990
|
+
/* @__PURE__ */ jsx("div", { children: user.email })
|
|
991
|
+
] }),
|
|
992
|
+
/* @__PURE__ */ jsx("a", { href: target, role: "menuitem", style: { display: "block", padding: "8px 10px", fontSize: 13, color: primary, textDecoration: "none" }, children: "Account" }),
|
|
993
|
+
/* @__PURE__ */ jsx(
|
|
994
|
+
"button",
|
|
995
|
+
{
|
|
996
|
+
role: "menuitem",
|
|
997
|
+
type: "button",
|
|
998
|
+
onClick: signOut2,
|
|
999
|
+
style: { display: "block", width: "100%", textAlign: "left", padding: "8px 10px", fontSize: 13, background: "transparent", border: "none", cursor: "pointer", color: "#b91c1c" },
|
|
1000
|
+
children: "Sign out"
|
|
1001
|
+
}
|
|
1002
|
+
)
|
|
1003
|
+
] }) : null
|
|
1004
|
+
]
|
|
1005
|
+
}
|
|
1006
|
+
);
|
|
770
1007
|
}
|
|
771
1008
|
function UserProfile({ iqAuthBaseUrl, className }) {
|
|
1009
|
+
const branding = useResolvedSdkBranding(iqAuthBaseUrl);
|
|
772
1010
|
const [user, setUser] = useState(null);
|
|
773
1011
|
const [oldPassword, setOldPassword] = useState("");
|
|
774
1012
|
const [newPassword, setNewPassword] = useState("");
|
|
@@ -802,8 +1040,8 @@ function UserProfile({ iqAuthBaseUrl, className }) {
|
|
|
802
1040
|
await fetch(`${iqAuthBaseUrl.replace(/\/$/, "")}/api/v1/auth/sessions/${sessionId}`, { method: "DELETE", credentials: "include" });
|
|
803
1041
|
setSessions((prev) => prev.filter((s) => s.id !== sessionId));
|
|
804
1042
|
};
|
|
805
|
-
if (!user) return /* @__PURE__ */ jsx(Shell, { branding
|
|
806
|
-
return /* @__PURE__ */ jsxs(Shell, { branding
|
|
1043
|
+
if (!user) return /* @__PURE__ */ jsx(Shell, { branding, className, children: /* @__PURE__ */ jsx("p", { children: "Loading account\u2026" }) });
|
|
1044
|
+
return /* @__PURE__ */ jsxs(Shell, { branding, className, children: [
|
|
807
1045
|
/* @__PURE__ */ jsx("h2", { style: { fontSize: 20, fontWeight: 600, margin: "0 0 12px" }, children: "Your account" }),
|
|
808
1046
|
/* @__PURE__ */ jsxs("section", { "aria-labelledby": "iqauth-profile", style: { marginBottom: 20 }, children: [
|
|
809
1047
|
/* @__PURE__ */ jsx("h3", { id: "iqauth-profile", style: { fontSize: 14, fontWeight: 600 }, children: "Profile" }),
|
|
@@ -838,6 +1076,8 @@ function UserProfile({ iqAuthBaseUrl, className }) {
|
|
|
838
1076
|
] });
|
|
839
1077
|
}
|
|
840
1078
|
function OrganizationSwitcher({ iqAuthBaseUrl, onSwitched, className }) {
|
|
1079
|
+
const branding = useResolvedSdkBranding(iqAuthBaseUrl);
|
|
1080
|
+
const accent = branding?.accentColor || "#6366f1";
|
|
841
1081
|
const [memberships, setMemberships] = useState([]);
|
|
842
1082
|
const [activeTenantId, setActiveTenantId] = useState(null);
|
|
843
1083
|
const [open, setOpen] = useState(false);
|
|
@@ -863,55 +1103,64 @@ function OrganizationSwitcher({ iqAuthBaseUrl, onSwitched, className }) {
|
|
|
863
1103
|
}
|
|
864
1104
|
};
|
|
865
1105
|
const active = memberships.find((m) => m.tenantId === activeTenantId);
|
|
866
|
-
return /* @__PURE__ */ jsxs(
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
1106
|
+
return /* @__PURE__ */ jsxs(
|
|
1107
|
+
"div",
|
|
1108
|
+
{
|
|
1109
|
+
className,
|
|
1110
|
+
style: { position: "relative", display: "inline-block", ...brandStyle(branding) },
|
|
1111
|
+
"data-iqauth-sdk-orgswitcher": "",
|
|
1112
|
+
"data-branding-rev": branding?.brandingRev || "",
|
|
1113
|
+
children: [
|
|
1114
|
+
/* @__PURE__ */ jsx(
|
|
1115
|
+
"button",
|
|
1116
|
+
{
|
|
1117
|
+
type: "button",
|
|
1118
|
+
"aria-haspopup": "menu",
|
|
1119
|
+
"aria-expanded": open,
|
|
1120
|
+
onClick: () => setOpen((o) => !o),
|
|
1121
|
+
style: { background: "transparent", border: `1px solid ${accent}55`, color: branding?.primaryColor || "#0f172a", padding: "6px 12px", borderRadius: 6, cursor: "pointer", fontSize: 13 },
|
|
1122
|
+
children: active?.tenantName || active?.tenantSlug || "Select organization"
|
|
1123
|
+
}
|
|
1124
|
+
),
|
|
1125
|
+
open ? /* @__PURE__ */ jsx("div", { role: "menu", style: {
|
|
1126
|
+
position: "absolute",
|
|
1127
|
+
left: 0,
|
|
1128
|
+
top: 36,
|
|
1129
|
+
minWidth: 220,
|
|
1130
|
+
background: "#fff",
|
|
1131
|
+
border: "1px solid rgba(15,23,42,0.12)",
|
|
1132
|
+
borderRadius: 8,
|
|
1133
|
+
boxShadow: "0 4px 12px rgba(0,0,0,0.08)",
|
|
1134
|
+
padding: 8,
|
|
1135
|
+
zIndex: 100
|
|
1136
|
+
}, children: memberships.length === 0 ? /* @__PURE__ */ jsx("p", { style: { fontSize: 13, opacity: 0.6, padding: "4px 6px" }, children: "No memberships" }) : memberships.map((m) => /* @__PURE__ */ jsxs(
|
|
1137
|
+
"button",
|
|
1138
|
+
{
|
|
1139
|
+
role: "menuitem",
|
|
1140
|
+
type: "button",
|
|
1141
|
+
onClick: () => switchTo(m.tenantId),
|
|
1142
|
+
style: {
|
|
1143
|
+
display: "block",
|
|
1144
|
+
width: "100%",
|
|
1145
|
+
textAlign: "left",
|
|
1146
|
+
padding: "8px 10px",
|
|
1147
|
+
background: m.tenantId === activeTenantId ? `${accent}14` : "transparent",
|
|
1148
|
+
border: "none",
|
|
1149
|
+
borderRadius: 4,
|
|
1150
|
+
cursor: "pointer",
|
|
1151
|
+
fontSize: 13,
|
|
1152
|
+
color: "#0f172a"
|
|
1153
|
+
},
|
|
1154
|
+
children: [
|
|
1155
|
+
/* @__PURE__ */ jsx("div", { style: { fontWeight: 500 }, children: m.tenantName || m.tenantSlug || m.tenantId }),
|
|
1156
|
+
/* @__PURE__ */ jsx("div", { style: { fontSize: 11, opacity: 0.6 }, children: m.roles.join(", ") })
|
|
1157
|
+
]
|
|
1158
|
+
},
|
|
1159
|
+
m.tenantId
|
|
1160
|
+
)) }) : null
|
|
1161
|
+
]
|
|
1162
|
+
}
|
|
1163
|
+
);
|
|
915
1164
|
}
|
|
916
1165
|
var __version__ = "phase-bc-1.0.0";
|
|
917
1166
|
export {
|
|
@@ -926,10 +1175,13 @@ export {
|
|
|
926
1175
|
UserButton,
|
|
927
1176
|
UserProfile,
|
|
928
1177
|
__version__,
|
|
1178
|
+
isSilentSsoEligible,
|
|
1179
|
+
sanitizeBrandCss,
|
|
929
1180
|
useAuth,
|
|
930
1181
|
useAuthFetch,
|
|
931
1182
|
useIQAuthSignInContext,
|
|
932
1183
|
useOrganization,
|
|
1184
|
+
useResolvedSdkBranding,
|
|
933
1185
|
useSession,
|
|
934
1186
|
useUser
|
|
935
1187
|
};
|