@luminaryworks/auth-react 0.3.2 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -24,7 +24,7 @@ On first 401: try refresh → else open reauth UI (overlay + OIDC **popup**, not
24
24
 
25
25
  ## Headless login panel
26
26
 
27
- Branded panel with **social buttons** (auto-loaded from IdP Experience `socialConnectors` — google / github / x / …) plus **unified account** password. Social uses `direct_sign_in=social:<target>`. Buttons are hidden when the IdP has no social connectors (do not invent Google/GitHub — that dumped users on Logto `/sign-in`).
27
+ Branded panel with **social buttons** (auto-loaded from IdP Experience `socialConnectors` — google / github / x / …) plus **unified account** password. The default `LogtoExperienceAdapter` keeps Logto's `direct_sign_in=social:<target>` parameter inside provider-specific code. Buttons are hidden when the IdP has no social connectors (do not invent Google/GitHub — that dumped users on Logto `/sign-in`).
28
28
 
29
29
  Styles ship as **CSS Modules (SCSS)**. The built bundle auto-injects panel CSS in the browser. Optional explicit import (SSR / style control):
30
30
 
@@ -56,9 +56,42 @@ Override layout via `className` / `style` on the root.
56
56
  |------|---------|--------|
57
57
  | `showSocialConnectors` | `true` | `false` skips fetch and hides divider + social buttons |
58
58
  | `socialProviders` | `"auto"` | allowlist, or `[]` (same effect as `showSocialConnectors={false}`) |
59
+ | `experienceAdapter` | `LogtoExperienceAdapter` | optional custom `LoginExperienceAdapter` |
59
60
 
60
61
  IdP hosted `/sign-in` social row layout: `node scripts/apply-branding.mjs` (customCss wrap). Enable connectors: `ensure-sign-in-experience.mjs` + `verify-social-direct-signin.mjs`.
61
62
 
63
+ ### Login experience adapters
64
+
65
+ `HeadlessLoginPanel` delegates non-standard password and social-connector flows
66
+ to `LoginExperienceAdapter`; standard OIDC authorization code + PKCE remains in
67
+ the OIDC client. Adapter methods are optional and are used only when both the
68
+ matching capability and method are present. Without password support, the panel
69
+ renders `labels.submitSso` and starts a standard hosted OIDC flow. Logto is the
70
+ only built-in provider:
71
+
72
+ ```ts
73
+ import {
74
+ createLoginExperienceAdapter,
75
+ LogtoExperienceAdapter,
76
+ resolveLoginExperienceAdapter,
77
+ type LoginExperienceAdapter,
78
+ type LoginExperienceCapability,
79
+ } from "@luminaryworks/auth-react";
80
+
81
+ const logto = new LogtoExperienceAdapter();
82
+ const sameDefault = createLoginExperienceAdapter("logto");
83
+ const resolved = resolveLoginExperienceAdapter(logto);
84
+
85
+ // Hosted-only enterprise IdP: no Experience API methods are required.
86
+ const hostedOnly = {
87
+ provider: "enterprise",
88
+ capabilities: [],
89
+ } satisfies LoginExperienceAdapter;
90
+ ```
91
+
92
+ Existing `experiencePasswordSignIn` and `fetchSocialConnectors` imports remain
93
+ available as compatibility functions backed by the default Logto adapter.
94
+
62
95
  ## Popup callback
63
96
 
64
97
  Callback route must detect popup windows and call `handleSignInPopupCallback` (do not SSO-exchange inside the popup).
package/dist/index.d.ts CHANGED
@@ -45,9 +45,12 @@ declare function createUserManager(config: LuminaryIdpConfig): UserManager;
45
45
  declare function resetUserManager(): void;
46
46
  interface SignInOptions {
47
47
  returnUrl?: string;
48
+ /** Provider-specific authorize parameters supplied by an experience adapter. */
49
+ extraQueryParams?: Record<string, string>;
48
50
  /**
49
51
  * Logto direct sign-in, e.g. `social:google` / `social:github` / `sso:<connectorId>`.
50
52
  * Skips the hosted password page and opens the provider immediately.
53
+ * @deprecated Prefer a LoginExperienceAdapter, which supplies extraQueryParams.
51
54
  */
52
55
  directSignIn?: string;
53
56
  }
@@ -83,10 +86,17 @@ declare function clearStoredSession(config: LuminaryIdpConfig): void;
83
86
  declare function getCurrentUser(config: LuminaryIdpConfig): Promise<LuminaryAuthSession | null>;
84
87
 
85
88
  /**
86
- * Logto Experience API (Headless) client.
87
- * Prefer same-origin Experience base (SPA proxies /api/experience) so cookies work on HTTP localhost.
88
- * @see https://docs.logto.io/docs/recipes/customize-token-claims (Experience API recipes)
89
+ * Capabilities exposed by a headless login-experience provider.
90
+ *
91
+ * Consumers can use these flags to avoid assuming that every provider supports
92
+ * Logto's password, connector-discovery, or direct social-login flows.
89
93
  */
94
+ declare const LOGIN_EXPERIENCE_CAPABILITIES: {
95
+ readonly passwordSignIn: "password-sign-in";
96
+ readonly socialConnectors: "social-connectors";
97
+ readonly socialDirectSignIn: "social-direct-sign-in";
98
+ };
99
+ type LoginExperienceCapability = (typeof LOGIN_EXPERIENCE_CAPABILITIES)[keyof typeof LOGIN_EXPERIENCE_CAPABILITIES];
90
100
  type ExperienceIdentifierType = "email" | "username" | "phone";
91
101
  interface ExperiencePasswordSignInInput {
92
102
  /** Experience API origin (no trailing slash). Prefer SPA origin when proxied. */
@@ -108,39 +118,69 @@ interface ExperiencePasswordSignInResult {
108
118
  redirectTo?: string;
109
119
  raw?: unknown;
110
120
  }
111
- /**
112
- * Force authorize onto the Experience/SPA origin so Set-Cookie lands on the same
113
- * host as subsequent `/api/experience` calls (dev proxy strips Domain).
114
- */
115
- declare function sameOriginAuthorizeUrl(authorizeUrl: string, apiBase: string): string;
116
- /**
117
- * Headless password sign-in via Logto Experience API.
118
- * Requires an OIDC interaction cookie (see {@link bootstrapOidcInteraction}) and
119
- * same-site Experience calls (SPA proxy or Auth Gateway on the SPA origin).
120
- *
121
- * On success, follow {@link ExperiencePasswordSignInResult.redirectTo} in the same
122
- * window — that URL completes the PKCE round-trip started by createSigninRequest.
123
- * Do not start a second authorize (that shows Logto `/sign-in` again).
124
- *
125
- * Tries the guessed identifier type first, then the alternate email/username so
126
- * users can sign in with either when both methods are enabled on the IdP.
127
- */
128
- declare function experiencePasswordSignIn(input: ExperiencePasswordSignInInput): Promise<ExperiencePasswordSignInResult>;
129
121
  interface ExperienceSocialConnector {
130
122
  id: string;
131
123
  target: string;
132
124
  name: string;
133
125
  logo?: string;
134
126
  }
135
- /**
136
- * Public Logto sign-in experience (no auth). Returns enabled social connectors
137
- * in SIE order — use for Headless social buttons (google / github / x / …).
138
- */
139
- declare function fetchSocialConnectors(input: {
127
+ interface FetchSocialConnectorsInput {
140
128
  /** Same origin as Experience / IdP (e.g. SPA proxy or http://localhost:3001). */
141
129
  apiBase: string;
142
130
  appId?: string;
143
- }): Promise<ExperienceSocialConnector[]>;
131
+ }
132
+ interface SocialSignInRequest {
133
+ /** Provider-specific authorize parameters, passed through by the OIDC client. */
134
+ extraQueryParams?: Record<string, string>;
135
+ }
136
+ /**
137
+ * Provider boundary for non-standard login-experience APIs.
138
+ *
139
+ * Standard OIDC redirect/popup and PKCE handling intentionally remain in the
140
+ * OIDC client. Only provider-specific Experience operations belong here.
141
+ */
142
+ interface LoginExperienceAdapter {
143
+ readonly provider: string;
144
+ readonly capabilities: readonly LoginExperienceCapability[];
145
+ experiencePasswordSignIn?(input: ExperiencePasswordSignInInput): Promise<ExperiencePasswordSignInResult>;
146
+ fetchSocialConnectors?(input: FetchSocialConnectorsInput): Promise<ExperienceSocialConnector[]>;
147
+ createSocialSignInRequest?(target: string): SocialSignInRequest;
148
+ }
149
+ type LoginExperienceProvider = "logto";
150
+ /**
151
+ * Factory for built-in providers. Logto is intentionally the only built-in
152
+ * adapter; products can supply their own adapter without shipping fake stubs.
153
+ */
154
+ declare function createLoginExperienceAdapter(provider?: LoginExperienceProvider): LoginExperienceAdapter;
155
+ /** Resolve an explicit product adapter, or the backward-compatible Logto default. */
156
+ declare function resolveLoginExperienceAdapter(adapter?: LoginExperienceAdapter | null): LoginExperienceAdapter;
157
+
158
+ /**
159
+ * Logto Experience API (Headless) adapter.
160
+ * Prefer same-origin Experience base (SPA proxies /api/experience) so cookies
161
+ * work on HTTP localhost.
162
+ */
163
+
164
+ /**
165
+ * Force authorize onto the Experience/SPA origin so Set-Cookie lands on the
166
+ * same host as subsequent `/api/experience` calls (dev proxy strips Domain).
167
+ */
168
+ declare function sameOriginAuthorizeUrl(authorizeUrl: string, apiBase: string): string;
169
+ /** Build Logto's provider-specific direct sign-in authorize parameter. */
170
+ declare function createLogtoDirectSignInRequest(directSignIn: string): SocialSignInRequest;
171
+ /** Built-in adapter for Logto's non-standard Experience API. */
172
+ declare class LogtoExperienceAdapter implements LoginExperienceAdapter {
173
+ readonly provider = "logto";
174
+ readonly capabilities: readonly LoginExperienceCapability[];
175
+ experiencePasswordSignIn(input: ExperiencePasswordSignInInput): Promise<ExperiencePasswordSignInResult>;
176
+ fetchSocialConnectors(input: FetchSocialConnectorsInput): Promise<ExperienceSocialConnector[]>;
177
+ createSocialSignInRequest(target: string): SocialSignInRequest;
178
+ }
179
+
180
+ /** @deprecated Use a LoginExperienceAdapter instance. */
181
+ declare function experiencePasswordSignIn(input: ExperiencePasswordSignInInput): Promise<ExperiencePasswordSignInResult>;
182
+ /** @deprecated Use a LoginExperienceAdapter instance. */
183
+ declare function fetchSocialConnectors(input: FetchSocialConnectorsInput): Promise<ExperienceSocialConnector[]>;
144
184
 
145
185
  /**
146
186
  * AuthGate — single-flight 401 recovery with optional token refresh + reauth UI.
@@ -235,7 +275,7 @@ interface HeadlessLoginLabels {
235
275
  identifierPlaceholder?: string;
236
276
  passwordPlaceholder?: string;
237
277
  submitPassword?: string;
238
- /** @deprecated Use social buttons; kept for backward-compatible label overrides. */
278
+ /** Hosted OIDC button shown when the adapter has no password capability. */
239
279
  submitSso?: string;
240
280
  submitGoogle?: string;
241
281
  submitGithub?: string;
@@ -248,6 +288,8 @@ interface HeadlessLoginLabels {
248
288
  }
249
289
  interface HeadlessLoginPanelProps {
250
290
  config: Partial<LuminaryIdpConfig>;
291
+ /** Login-experience provider. Defaults to the built-in Logto adapter. */
292
+ experienceAdapter?: LoginExperienceAdapter;
251
293
  /** Product display name shown as brand signal */
252
294
  productName: string;
253
295
  logoSrc?: string;
@@ -290,7 +332,7 @@ interface HeadlessLoginPanelProps {
290
332
  }
291
333
  /** Shared default accent for product login panels. */
292
334
  declare const DEFAULT_LOGIN_THEME_COLOR = "#3a84ff";
293
- declare function HeadlessLoginPanel({ config, productName, logoSrc, labels: labelsProp, returnUrl, mode, showSocialConnectors, socialProviders, showCancel, onCancel, onOidcSession, onExperienceRedirect, footer, className, style, themeColor, }: HeadlessLoginPanelProps): react.JSX.Element;
335
+ declare function HeadlessLoginPanel({ config, experienceAdapter: experienceAdapterProp, productName, logoSrc, labels: labelsProp, returnUrl, mode, showSocialConnectors, socialProviders, showCancel, onCancel, onOidcSession, onExperienceRedirect, footer, className, style, themeColor, }: HeadlessLoginPanelProps): react.JSX.Element;
294
336
 
295
337
  interface ReauthOverlayProps {
296
338
  config: Partial<LuminaryIdpConfig>;
@@ -353,4 +395,4 @@ declare function createPostLoginPathHelpers(options: PostLoginPathOptions): {
353
395
  isUnsafeReturnPath: (path: string) => boolean;
354
396
  };
355
397
 
356
- export { type AuthGateConfig, type AuthGatePhase, AuthGateProvider, type AuthGateProviderProps, type AuthGateSnapshot, DEFAULT_LOGIN_THEME_COLOR, type ExperienceIdentifierType, type ExperiencePasswordSignInInput, type ExperiencePasswordSignInResult, type ExperienceSocialConnector, type HeadlessLoginLabels, HeadlessLoginPanel, type HeadlessLoginPanelProps, LuminaryAuthProvider, type LuminaryAuthProviderProps, type LuminaryAuthSession, type LuminaryIdpConfig, type PostLoginPathOptions, ReauthOverlay, type ReauthOverlayProps, type SignInOptions, type SocialProviderTarget, type UnauthorizedDisposition, authGate, clearStoredSession, createPostLoginPathHelpers, createUserManager, experiencePasswordSignIn, fetchSocialConnectors, getCurrentUser, getStoredAccessToken, handleSignInCallback, handleSignInPopupCallback, isIdpConfigured, isOidcPopupWindow, prepareSignInRequestUrl, readIdpConfigFromEnv, resetUserManager, resolveExperienceApiBase, resolveIssuer, sameOriginAuthorizeUrl, signInPopup, signInRedirect, signOutRedirect, useAuthGate, useAuthGateOptional, useLuminaryAuth, withAuthGateRetry };
398
+ export { type AuthGateConfig, type AuthGatePhase, AuthGateProvider, type AuthGateProviderProps, type AuthGateSnapshot, DEFAULT_LOGIN_THEME_COLOR, type ExperienceIdentifierType, type ExperiencePasswordSignInInput, type ExperiencePasswordSignInResult, type ExperienceSocialConnector, type FetchSocialConnectorsInput, type HeadlessLoginLabels, HeadlessLoginPanel, type HeadlessLoginPanelProps, LOGIN_EXPERIENCE_CAPABILITIES, type LoginExperienceAdapter, type LoginExperienceCapability, type LoginExperienceProvider, LogtoExperienceAdapter, LuminaryAuthProvider, type LuminaryAuthProviderProps, type LuminaryAuthSession, type LuminaryIdpConfig, type PostLoginPathOptions, ReauthOverlay, type ReauthOverlayProps, type SignInOptions, type SocialProviderTarget, type SocialSignInRequest, type UnauthorizedDisposition, authGate, clearStoredSession, createLoginExperienceAdapter, createLogtoDirectSignInRequest, createPostLoginPathHelpers, createUserManager, experiencePasswordSignIn, fetchSocialConnectors, getCurrentUser, getStoredAccessToken, handleSignInCallback, handleSignInPopupCallback, isIdpConfigured, isOidcPopupWindow, prepareSignInRequestUrl, readIdpConfigFromEnv, resetUserManager, resolveExperienceApiBase, resolveIssuer, resolveLoginExperienceAdapter, sameOriginAuthorizeUrl, signInPopup, signInRedirect, signOutRedirect, useAuthGate, useAuthGateOptional, useLuminaryAuth, withAuthGateRetry };
package/dist/index.js CHANGED
@@ -39,6 +39,193 @@ function readIdpConfigFromEnv(env) {
39
39
  experienceApiBase: resolveExperienceApiBase(env)
40
40
  };
41
41
  }
42
+
43
+ // src/login-experience-adapter.ts
44
+ var LOGIN_EXPERIENCE_CAPABILITIES = {
45
+ passwordSignIn: "password-sign-in",
46
+ socialConnectors: "social-connectors",
47
+ socialDirectSignIn: "social-direct-sign-in"
48
+ };
49
+ function createLoginExperienceAdapter(provider = "logto") {
50
+ switch (provider) {
51
+ case "logto":
52
+ return new LogtoExperienceAdapter();
53
+ }
54
+ }
55
+ var defaultAdapter;
56
+ function resolveLoginExperienceAdapter(adapter) {
57
+ if (adapter) return adapter;
58
+ defaultAdapter ??= createLoginExperienceAdapter();
59
+ return defaultAdapter;
60
+ }
61
+
62
+ // src/logto-experience-adapter.ts
63
+ function experienceUrl(apiBase, path) {
64
+ return `${apiBase.replace(/\/$/, "")}/api/experience${path}`;
65
+ }
66
+ async function experienceFetch(apiBase, path, init) {
67
+ const res = await fetch(experienceUrl(apiBase, path), {
68
+ credentials: "include",
69
+ ...init,
70
+ headers: {
71
+ "Content-Type": "application/json",
72
+ Accept: "application/json",
73
+ ...init.headers ?? {}
74
+ }
75
+ });
76
+ const text = await res.text();
77
+ let data = null;
78
+ if (text) {
79
+ try {
80
+ data = JSON.parse(text);
81
+ } catch {
82
+ data = text;
83
+ }
84
+ }
85
+ if (!res.ok) {
86
+ const msg = data && typeof data === "object" && data !== null && "message" in data ? String(data.message) : `Experience API ${res.status}`;
87
+ throw new Error(msg);
88
+ }
89
+ return data;
90
+ }
91
+ function guessIdentifierType(identifier) {
92
+ if (identifier.includes("@")) return "email";
93
+ if (/^\+?\d{6,}$/.test(identifier.trim())) return "phone";
94
+ return "username";
95
+ }
96
+ function sameOriginAuthorizeUrl(authorizeUrl, apiBase) {
97
+ const u = new URL(authorizeUrl);
98
+ const base = new URL(apiBase);
99
+ if (u.origin === base.origin) return authorizeUrl;
100
+ return `${base.origin}${u.pathname}${u.search}${u.hash}`;
101
+ }
102
+ async function bootstrapOidcInteraction(input) {
103
+ if (!input.issuer || !input.clientId || !input.redirectUri) return;
104
+ if (typeof document === "undefined") return;
105
+ const config = {
106
+ issuer: input.issuer,
107
+ clientId: input.clientId,
108
+ redirectUri: input.redirectUri,
109
+ audience: input.audience,
110
+ scopes: input.scopes,
111
+ experienceApiBase: input.apiBase
112
+ };
113
+ const signinUrl = await prepareSignInRequestUrl(config, {
114
+ returnUrl: input.returnUrl
115
+ });
116
+ const authorizeUrl = sameOriginAuthorizeUrl(signinUrl, input.apiBase);
117
+ await new Promise((resolve) => {
118
+ const iframe = document.createElement("iframe");
119
+ iframe.setAttribute("aria-hidden", "true");
120
+ iframe.tabIndex = -1;
121
+ iframe.style.cssText = "position:absolute;width:0;height:0;border:0;visibility:hidden";
122
+ let settled = false;
123
+ const finish = () => {
124
+ if (settled) return;
125
+ settled = true;
126
+ iframe.remove();
127
+ resolve();
128
+ };
129
+ iframe.addEventListener("load", () => {
130
+ window.setTimeout(finish, 400);
131
+ });
132
+ iframe.src = authorizeUrl;
133
+ document.body.appendChild(iframe);
134
+ window.setTimeout(finish, 2500);
135
+ });
136
+ }
137
+ function createLogtoDirectSignInRequest(directSignIn) {
138
+ return { extraQueryParams: { direct_sign_in: directSignIn } };
139
+ }
140
+ var LogtoExperienceAdapter = class {
141
+ provider = "logto";
142
+ capabilities = [
143
+ LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn,
144
+ LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors,
145
+ LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn
146
+ ];
147
+ async experiencePasswordSignIn(input) {
148
+ const { apiBase, identifier, password } = input;
149
+ await bootstrapOidcInteraction(input);
150
+ const primary = input.identifierType ?? guessIdentifierType(identifier);
151
+ const alternates = primary === "phone" ? [primary] : primary === "email" ? ["email", "username"] : ["username", "email"];
152
+ let lastError;
153
+ for (const identifierType of alternates) {
154
+ try {
155
+ await experienceFetch(apiBase, "", {
156
+ method: "PUT",
157
+ body: JSON.stringify({ interactionEvent: "SignIn" })
158
+ });
159
+ const verified = await experienceFetch(
160
+ apiBase,
161
+ "/verification/password",
162
+ {
163
+ method: "POST",
164
+ body: JSON.stringify({
165
+ identifier: { type: identifierType, value: identifier },
166
+ password
167
+ })
168
+ }
169
+ );
170
+ const verificationId = verified?.verificationId;
171
+ if (!verificationId) {
172
+ throw new Error("Experience API did not return verificationId");
173
+ }
174
+ await experienceFetch(apiBase, "/identification", {
175
+ method: "POST",
176
+ body: JSON.stringify({ verificationId })
177
+ });
178
+ const submitted = await experienceFetch(
179
+ apiBase,
180
+ "/submit",
181
+ {
182
+ method: "POST",
183
+ body: JSON.stringify({})
184
+ }
185
+ );
186
+ return { redirectTo: submitted?.redirectTo, raw: submitted };
187
+ } catch (error) {
188
+ lastError = error instanceof Error ? error : new Error(String(error));
189
+ }
190
+ }
191
+ throw lastError ?? new Error("Experience password sign-in failed");
192
+ }
193
+ async fetchSocialConnectors(input) {
194
+ const url = new URL(`${input.apiBase.replace(/\/$/, "")}/api/.well-known/sign-in-exp`);
195
+ if (input.appId?.trim()) url.searchParams.set("appId", input.appId.trim());
196
+ const res = await fetch(url.toString(), {
197
+ // Public metadata — omit cookies so browsers do not require credentialed CORS.
198
+ credentials: "omit",
199
+ headers: { Accept: "application/json" }
200
+ });
201
+ if (!res.ok) {
202
+ throw new Error(`sign-in-exp ${res.status}`);
203
+ }
204
+ const data = await res.json();
205
+ return (data.socialConnectors ?? []).filter(
206
+ (connector) => Boolean(connector?.id && connector?.target)
207
+ ).map((connector) => ({
208
+ id: connector.id,
209
+ target: connector.target,
210
+ name: localizeName(connector.name) || titleCase(connector.target),
211
+ logo: connector.logo
212
+ }));
213
+ }
214
+ createSocialSignInRequest(target) {
215
+ return createLogtoDirectSignInRequest(`social:${target}`);
216
+ }
217
+ };
218
+ function localizeName(name) {
219
+ if (!name) return "";
220
+ if (typeof name === "string") return name;
221
+ return name["zh-CN"] || name.en || Object.values(name)[0] || "";
222
+ }
223
+ function titleCase(target) {
224
+ if (!target) return "";
225
+ return target.charAt(0).toUpperCase() + target.slice(1);
226
+ }
227
+
228
+ // src/oidc-client.ts
42
229
  var manager = null;
43
230
  function storageKey(config) {
44
231
  return config.tokenStorageKey ?? "luminary_access_token";
@@ -95,9 +282,14 @@ function resetUserManager() {
95
282
  function signInArgs(config, options) {
96
283
  const normalized = typeof options === "string" ? { returnUrl: options } : options ?? {};
97
284
  const resource = config.audience?.trim();
98
- const extraQueryParams = {};
285
+ const extraQueryParams = { ...normalized.extraQueryParams };
99
286
  if (resource) extraQueryParams.resource = resource;
100
- if (normalized.directSignIn) extraQueryParams.direct_sign_in = normalized.directSignIn;
287
+ if (normalized.directSignIn) {
288
+ Object.assign(
289
+ extraQueryParams,
290
+ createLogtoDirectSignInRequest(normalized.directSignIn).extraQueryParams
291
+ );
292
+ }
101
293
  return {
102
294
  state: normalized.returnUrl ? { returnUrl: normalized.returnUrl } : void 0,
103
295
  extraQueryParams: Object.keys(extraQueryParams).length ? extraQueryParams : void 0
@@ -189,151 +381,19 @@ async function getCurrentUser(config) {
189
381
  }
190
382
 
191
383
  // src/experience-client.ts
192
- function experienceUrl(apiBase, path) {
193
- return `${apiBase.replace(/\/$/, "")}/api/experience${path}`;
194
- }
195
- async function experienceFetch(apiBase, path, init) {
196
- const res = await fetch(experienceUrl(apiBase, path), {
197
- credentials: "include",
198
- ...init,
199
- headers: {
200
- "Content-Type": "application/json",
201
- Accept: "application/json",
202
- ...init.headers ?? {}
203
- }
204
- });
205
- const text = await res.text();
206
- let data = null;
207
- if (text) {
208
- try {
209
- data = JSON.parse(text);
210
- } catch {
211
- data = text;
212
- }
213
- }
214
- if (!res.ok) {
215
- const msg = data && typeof data === "object" && data !== null && "message" in data ? String(data.message) : `Experience API ${res.status}`;
216
- throw new Error(msg);
217
- }
218
- return data;
219
- }
220
- function guessIdentifierType(identifier) {
221
- if (identifier.includes("@")) return "email";
222
- if (/^\+?\d{6,}$/.test(identifier.trim())) return "phone";
223
- return "username";
224
- }
225
- function sameOriginAuthorizeUrl(authorizeUrl, apiBase) {
226
- const u = new URL(authorizeUrl);
227
- const base = new URL(apiBase);
228
- if (u.origin === base.origin) return authorizeUrl;
229
- return `${base.origin}${u.pathname}${u.search}${u.hash}`;
230
- }
231
- async function bootstrapOidcInteraction(input) {
232
- if (!input.issuer || !input.clientId || !input.redirectUri) return;
233
- if (typeof document === "undefined") return;
234
- const config = {
235
- issuer: input.issuer,
236
- clientId: input.clientId,
237
- redirectUri: input.redirectUri,
238
- audience: input.audience,
239
- scopes: input.scopes,
240
- experienceApiBase: input.apiBase
241
- };
242
- const signinUrl = await prepareSignInRequestUrl(config, {
243
- returnUrl: input.returnUrl
244
- });
245
- const authorizeUrl = sameOriginAuthorizeUrl(signinUrl, input.apiBase);
246
- await new Promise((resolve) => {
247
- const iframe = document.createElement("iframe");
248
- iframe.setAttribute("aria-hidden", "true");
249
- iframe.tabIndex = -1;
250
- iframe.style.cssText = "position:absolute;width:0;height:0;border:0;visibility:hidden";
251
- let settled = false;
252
- const finish = () => {
253
- if (settled) return;
254
- settled = true;
255
- iframe.remove();
256
- resolve();
257
- };
258
- iframe.addEventListener("load", () => {
259
- window.setTimeout(finish, 400);
260
- });
261
- iframe.src = authorizeUrl;
262
- document.body.appendChild(iframe);
263
- window.setTimeout(finish, 2500);
264
- });
265
- }
266
- async function experiencePasswordSignIn(input) {
267
- const { apiBase, identifier, password } = input;
268
- await bootstrapOidcInteraction(input);
269
- const primary = input.identifierType ?? guessIdentifierType(identifier);
270
- const alternates = primary === "phone" ? [primary] : primary === "email" ? ["email", "username"] : ["username", "email"];
271
- let lastError;
272
- for (const identifierType of alternates) {
273
- try {
274
- await experienceFetch(apiBase, "", {
275
- method: "PUT",
276
- body: JSON.stringify({ interactionEvent: "SignIn" })
277
- });
278
- const verified = await experienceFetch(
279
- apiBase,
280
- "/verification/password",
281
- {
282
- method: "POST",
283
- body: JSON.stringify({
284
- identifier: { type: identifierType, value: identifier },
285
- password
286
- })
287
- }
288
- );
289
- const verificationId = verified?.verificationId;
290
- if (!verificationId) {
291
- throw new Error("Experience API did not return verificationId");
292
- }
293
- await experienceFetch(apiBase, "/identification", {
294
- method: "POST",
295
- body: JSON.stringify({ verificationId })
296
- });
297
- const submitted = await experienceFetch(apiBase, "/submit", {
298
- method: "POST",
299
- body: JSON.stringify({})
300
- });
301
- return { redirectTo: submitted?.redirectTo, raw: submitted };
302
- } catch (e) {
303
- lastError = e instanceof Error ? e : new Error(String(e));
304
- }
384
+ function experiencePasswordSignIn(input) {
385
+ const adapter = resolveLoginExperienceAdapter();
386
+ if (!adapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn) || !adapter.experiencePasswordSignIn) {
387
+ return Promise.reject(new Error("Login experience does not support password sign-in"));
305
388
  }
306
- throw lastError ?? new Error("Experience password sign-in failed");
389
+ return adapter.experiencePasswordSignIn(input);
307
390
  }
308
- async function fetchSocialConnectors(input) {
309
- const url = new URL(`${input.apiBase.replace(/\/$/, "")}/api/.well-known/sign-in-exp`);
310
- if (input.appId?.trim()) url.searchParams.set("appId", input.appId.trim());
311
- const res = await fetch(url.toString(), {
312
- // Public metadata — omit cookies so browsers do not require credentialed CORS.
313
- credentials: "omit",
314
- headers: { Accept: "application/json" }
315
- });
316
- if (!res.ok) {
317
- throw new Error(`sign-in-exp ${res.status}`);
391
+ function fetchSocialConnectors(input) {
392
+ const adapter = resolveLoginExperienceAdapter();
393
+ if (!adapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors) || !adapter.fetchSocialConnectors) {
394
+ return Promise.reject(new Error("Login experience does not support social connectors"));
318
395
  }
319
- const data = await res.json();
320
- return (data.socialConnectors ?? []).filter(
321
- (c) => Boolean(c?.id && c?.target)
322
- ).map((c) => ({
323
- id: c.id,
324
- target: c.target,
325
- name: localizeName(c.name) || titleCase(c.target),
326
- logo: c.logo
327
- }));
328
- }
329
- function localizeName(name) {
330
- if (!name) return "";
331
- if (typeof name === "string") return name;
332
- return name["zh-CN"] || name.en || Object.values(name)[0] || "";
333
- }
334
- function titleCase(target) {
335
- if (!target) return "";
336
- return target.charAt(0).toUpperCase() + target.slice(1);
396
+ return adapter.fetchSocialConnectors(input);
337
397
  }
338
398
 
339
399
  // src/auth-gate.ts
@@ -596,6 +656,7 @@ function cx(...parts) {
596
656
  }
597
657
  function HeadlessLoginPanel({
598
658
  config,
659
+ experienceAdapter: experienceAdapterProp,
599
660
  productName,
600
661
  logoSrc,
601
662
  labels: labelsProp,
@@ -612,6 +673,7 @@ function HeadlessLoginPanel({
612
673
  style,
613
674
  themeColor = DEFAULT_LOGIN_THEME_COLOR
614
675
  }) {
676
+ const experienceAdapter = resolveLoginExperienceAdapter(experienceAdapterProp);
615
677
  const labels = { ...defaults, ...labelsProp };
616
678
  const configured = isIdpConfigured(config);
617
679
  const [identifier, setIdentifier] = react.useState("");
@@ -624,7 +686,8 @@ function HeadlessLoginPanel({
624
686
  const [loading, setLoading] = react.useState(null);
625
687
  const [error, setError] = react.useState("");
626
688
  const [connectors, setConnectors] = react.useState([]);
627
- const socialEnabled = showSocialConnectors !== false && !(Array.isArray(socialProviders) && socialProviders.length === 0);
689
+ const socialEnabled = showSocialConnectors !== false && !(Array.isArray(socialProviders) && socialProviders.length === 0) && experienceAdapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors) && experienceAdapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn) && typeof experienceAdapter.fetchSocialConnectors === "function" && typeof experienceAdapter.createSocialSignInRequest === "function";
690
+ const passwordEnabled = experienceAdapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn) && typeof experienceAdapter.experiencePasswordSignIn === "function";
628
691
  react.useEffect(() => {
629
692
  const resetBusy = () => setLoading(null);
630
693
  window.addEventListener("pageshow", resetBusy);
@@ -635,7 +698,8 @@ function HeadlessLoginPanel({
635
698
  };
636
699
  }, []);
637
700
  react.useEffect(() => {
638
- if (!socialEnabled) {
701
+ const fetchConnectors = experienceAdapter.fetchSocialConnectors;
702
+ if (!socialEnabled || !fetchConnectors) {
639
703
  setConnectors([]);
640
704
  return;
641
705
  }
@@ -650,7 +714,7 @@ function HeadlessLoginPanel({
650
714
  if (!cancelled) setConnectors([]);
651
715
  return;
652
716
  }
653
- void fetchSocialConnectors({ apiBase: sieBase, appId: config.clientId }).then((list) => {
717
+ void fetchConnectors.call(experienceAdapter, { apiBase: sieBase, appId: config.clientId }).then((list) => {
654
718
  apply(list);
655
719
  }).catch(() => {
656
720
  if (!cancelled) setConnectors([]);
@@ -658,21 +722,46 @@ function HeadlessLoginPanel({
658
722
  return () => {
659
723
  cancelled = true;
660
724
  };
661
- }, [config.clientId, config.experienceApiBase, config.issuer, socialEnabled, socialProviders]);
662
- const runOidc = async (directSignIn) => {
725
+ }, [
726
+ config.clientId,
727
+ config.experienceApiBase,
728
+ config.issuer,
729
+ experienceAdapter,
730
+ socialEnabled,
731
+ socialProviders
732
+ ]);
733
+ const runOidc = async (experienceRequest) => {
663
734
  if (!configured) throw new Error("IdP not configured");
664
735
  if (mode === "redirect") {
665
- await signInRedirect(config, { returnUrl, directSignIn });
736
+ await signInRedirect(config, { returnUrl, ...experienceRequest });
666
737
  return;
667
738
  }
668
- const { session, returnUrl: next } = await signInPopup(config, { returnUrl, directSignIn });
739
+ const { session, returnUrl: next } = await signInPopup(config, {
740
+ returnUrl,
741
+ ...experienceRequest
742
+ });
669
743
  await onOidcSession?.(session, next);
670
744
  };
671
745
  const runSocial = async (target) => {
672
746
  setError("");
673
747
  setLoading(target);
674
748
  try {
675
- await runOidc(`social:${target}`);
749
+ if (!socialEnabled || !experienceAdapter.capabilities.includes(
750
+ LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn
751
+ ) || !experienceAdapter.createSocialSignInRequest) {
752
+ throw new Error("Login experience does not support direct social sign-in");
753
+ }
754
+ await runOidc(experienceAdapter.createSocialSignInRequest(target));
755
+ } catch (e) {
756
+ setError(e instanceof Error ? e.message : String(e));
757
+ setLoading(null);
758
+ }
759
+ };
760
+ const runHostedOidc = async () => {
761
+ setError("");
762
+ setLoading("sso");
763
+ try {
764
+ await runOidc();
676
765
  } catch (e) {
677
766
  setError(e instanceof Error ? e.message : String(e));
678
767
  setLoading(null);
@@ -695,7 +784,12 @@ function HeadlessLoginPanel({
695
784
  if (!apiBase) {
696
785
  throw new Error(labels.experienceUnavailable);
697
786
  }
698
- const result = await experiencePasswordSignIn({
787
+ if (!passwordEnabled || !experienceAdapter.capabilities.includes(
788
+ LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn
789
+ ) || !experienceAdapter.experiencePasswordSignIn) {
790
+ throw new Error(labels.experienceUnavailable);
791
+ }
792
+ const result = await experienceAdapter.experiencePasswordSignIn({
699
793
  apiBase,
700
794
  identifier: identifier.trim(),
701
795
  password,
@@ -729,7 +823,7 @@ function HeadlessLoginPanel({
729
823
  ] }),
730
824
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: HeadlessLoginPanel_module_default.subtitle, children: labels.subtitle }),
731
825
  configured ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
732
- /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => void runPassword(e), className: HeadlessLoginPanel_module_default.form, children: [
826
+ passwordEnabled ? /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => void runPassword(e), className: HeadlessLoginPanel_module_default.form, children: [
733
827
  /* @__PURE__ */ jsxRuntime.jsx(
734
828
  "input",
735
829
  {
@@ -771,7 +865,16 @@ function HeadlessLoginPanel({
771
865
  )
772
866
  ] }),
773
867
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: HeadlessLoginPanel_module_default.primaryBtn, disabled: busy || !identifier || !password, children: loading === "password" ? "\u2026" : labels.submitPassword })
774
- ] }),
868
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: HeadlessLoginPanel_module_default.form, children: /* @__PURE__ */ jsxRuntime.jsx(
869
+ "button",
870
+ {
871
+ type: "button",
872
+ className: HeadlessLoginPanel_module_default.primaryBtn,
873
+ disabled: busy,
874
+ onClick: () => void runHostedOidc(),
875
+ children: loading === "sso" ? "\u2026" : labels.submitSso
876
+ }
877
+ ) }),
775
878
  showHint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: HeadlessLoginPanel_module_default.hint, children: labels.hint }) : null,
776
879
  showSocial ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: HeadlessLoginPanel_module_default.divider, "aria-hidden": true, children: [
777
880
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: HeadlessLoginPanel_module_default.dividerLine }),
@@ -998,10 +1101,14 @@ function createPostLoginPathHelpers(options) {
998
1101
  exports.AuthGateProvider = AuthGateProvider;
999
1102
  exports.DEFAULT_LOGIN_THEME_COLOR = DEFAULT_LOGIN_THEME_COLOR;
1000
1103
  exports.HeadlessLoginPanel = HeadlessLoginPanel;
1104
+ exports.LOGIN_EXPERIENCE_CAPABILITIES = LOGIN_EXPERIENCE_CAPABILITIES;
1105
+ exports.LogtoExperienceAdapter = LogtoExperienceAdapter;
1001
1106
  exports.LuminaryAuthProvider = LuminaryAuthProvider;
1002
1107
  exports.ReauthOverlay = ReauthOverlay;
1003
1108
  exports.authGate = authGate;
1004
1109
  exports.clearStoredSession = clearStoredSession;
1110
+ exports.createLoginExperienceAdapter = createLoginExperienceAdapter;
1111
+ exports.createLogtoDirectSignInRequest = createLogtoDirectSignInRequest;
1005
1112
  exports.createPostLoginPathHelpers = createPostLoginPathHelpers;
1006
1113
  exports.createUserManager = createUserManager;
1007
1114
  exports.experiencePasswordSignIn = experiencePasswordSignIn;
@@ -1017,6 +1124,7 @@ exports.readIdpConfigFromEnv = readIdpConfigFromEnv;
1017
1124
  exports.resetUserManager = resetUserManager;
1018
1125
  exports.resolveExperienceApiBase = resolveExperienceApiBase;
1019
1126
  exports.resolveIssuer = resolveIssuer;
1127
+ exports.resolveLoginExperienceAdapter = resolveLoginExperienceAdapter;
1020
1128
  exports.sameOriginAuthorizeUrl = sameOriginAuthorizeUrl;
1021
1129
  exports.signInPopup = signInPopup;
1022
1130
  exports.signInRedirect = signInRedirect;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/types.ts","../src/oidc-client.ts","../src/experience-client.ts","../src/auth-gate.ts","../src/LuminaryAuthProvider.tsx","../src/HeadlessLoginPanel.module.scss","../src/HeadlessLoginPanel.tsx","../src/ReauthOverlay.tsx","../src/AuthGateProvider.tsx","../src/post-login-path.ts"],"names":["WebStorageStateStore","UserManager","OidcClient","createContext","useMemo","useState","useCallback","useEffect","jsx","useContext","panel","brand","logo","product","title","subtitle","form","socialStack","input","passwordField","passwordInput","passwordToggle","primaryBtn","socialBtn","socialLogo","logoFallback","cancelBtn","divider","dividerLine","dividerText","hint","error","footer","jsxs","Fragment","useSyncExternalStore","storageKey"],"mappings":"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","file":"index.js","sourcesContent":["export interface LuminaryIdpConfig {\n /**\n * OIDC issuer. Prefer Auth Gateway (`http://localhost:3010/oidc`) so products\n * stay IdP-agnostic; direct Logto issuer is OK for local MVP.\n */\n issuer: string;\n clientId: string;\n redirectUri: string;\n /**\n * Popup OIDC callback. Defaults to `redirectUri` (same `/auth/callback`).\n * Must be registered on the IdP application.\n */\n popupRedirectUri?: string;\n postLogoutRedirectUri?: string;\n scopes?: string;\n /** API resource indicator (access token `aud`) */\n audience?: string;\n /** localStorage key for access token */\n tokenStorageKey?: string;\n /**\n * Logto Experience API base (no trailing slash), e.g. Auth Gateway\n * `http://localhost:3010` or direct Logto `http://localhost:3001`.\n * When set, Headless password sign-in is attempted before OIDC popup fallback.\n */\n experienceApiBase?: string;\n}\n\nexport interface LuminaryAuthSession {\n accessToken: string;\n idToken?: string;\n expiresAt?: number;\n profile?: Record<string, unknown>;\n}\n\nexport function isIdpConfigured(config: Partial<LuminaryIdpConfig>): config is LuminaryIdpConfig {\n return Boolean(config.issuer && config.clientId && config.redirectUri);\n}\n\n/** Resolve issuer from Auth Gateway base URL or direct IDP_ISSUER. */\nexport function resolveIssuer(env: Record<string, string | undefined>): string | undefined {\n // Prefer explicit IdP issuer so JWT `iss` validation matches Logto.\n // Auth Gateway is a CORS/proxy front — set via VITE_AUTH_EXPERIENCE_URL / VITE_AUTH_GATEWAY_URL.\n const explicit = env.VITE_IDP_ISSUER ?? env.PUBLIC_IDP_ISSUER ?? env.IDP_ISSUER;\n if (explicit) return explicit;\n const gateway = env.VITE_AUTH_GATEWAY_URL ?? env.PUBLIC_AUTH_GATEWAY_URL ?? env.AUTH_GATEWAY_URL;\n if (gateway) return `${gateway.replace(/\\/$/, \"\")}/oidc`;\n return undefined;\n}\n\n/** Derive Experience API host from Gateway URL or by stripping `/oidc` from issuer. */\nexport function resolveExperienceApiBase(env: Record<string, string | undefined>): string | undefined {\n const explicit =\n env.VITE_AUTH_EXPERIENCE_URL ??\n env.PUBLIC_AUTH_EXPERIENCE_URL ??\n env.AUTH_EXPERIENCE_URL;\n if (explicit) return explicit.replace(/\\/$/, \"\");\n\n const gateway = env.VITE_AUTH_GATEWAY_URL ?? env.PUBLIC_AUTH_GATEWAY_URL ?? env.AUTH_GATEWAY_URL;\n if (gateway) return gateway.replace(/\\/$/, \"\");\n\n const issuer = resolveIssuer(env);\n if (!issuer) return undefined;\n return issuer.replace(/\\/$/, \"\").replace(/\\/oidc$/i, \"\");\n}\n\nexport function readIdpConfigFromEnv(env: Record<string, string | undefined>): Partial<LuminaryIdpConfig> {\n const redirectUri = env.VITE_IDP_REDIRECT_URI ?? env.PUBLIC_IDP_REDIRECT_URI ?? \"\";\n return {\n issuer: resolveIssuer(env),\n clientId: env.VITE_IDP_CLIENT_ID ?? env.PUBLIC_IDP_CLIENT_ID,\n redirectUri,\n popupRedirectUri: env.VITE_IDP_POPUP_REDIRECT_URI ?? env.PUBLIC_IDP_POPUP_REDIRECT_URI ?? redirectUri,\n postLogoutRedirectUri: env.VITE_IDP_POST_LOGOUT_URI ?? env.PUBLIC_IDP_POST_LOGOUT_URI,\n scopes: env.VITE_IDP_SCOPES ?? env.PUBLIC_IDP_SCOPES ?? \"openid profile email offline_access\",\n audience: env.VITE_IDP_AUDIENCE ?? env.PUBLIC_IDP_AUDIENCE,\n tokenStorageKey: env.VITE_IDP_TOKEN_KEY ?? \"luminary_access_token\",\n experienceApiBase: resolveExperienceApiBase(env),\n };\n}\n","import {\n OidcClient,\n UserManager,\n WebStorageStateStore,\n type User,\n} from \"oidc-client-ts\";\nimport type { LuminaryAuthSession, LuminaryIdpConfig } from \"./types\";\n\nlet manager: UserManager | null = null;\n\nfunction storageKey(config: LuminaryIdpConfig): string {\n return config.tokenStorageKey ?? \"luminary_access_token\";\n}\n\nfunction popupRedirectUri(config: LuminaryIdpConfig): string {\n return config.popupRedirectUri ?? config.redirectUri;\n}\n\nfunction sharedStateStore() {\n // localStorage so popup/redirect/Experience callback windows can resolve PKCE state.\n return new WebStorageStateStore({ store: window.localStorage });\n}\n\nfunction clientSettings(config: LuminaryIdpConfig) {\n const resource = config.audience?.trim() || undefined;\n return {\n authority: config.issuer.replace(/\\/$/, \"\"),\n metadataUrl: resolveOidcMetadataUrl(config),\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n post_logout_redirect_uri: config.postLogoutRedirectUri ?? config.redirectUri,\n response_type: \"code\" as const,\n scope: config.scopes ?? \"openid profile email offline_access\",\n stateStore: sharedStateStore(),\n extraQueryParams: resource ? { resource } : undefined,\n extraTokenParams: resource ? { resource } : undefined,\n };\n}\n\nfunction userManagerSettings(config: LuminaryIdpConfig) {\n const resource = config.audience?.trim() || undefined;\n return {\n ...clientSettings(config),\n popup_redirect_uri: popupRedirectUri(config),\n automaticSilentRenew: true,\n loadUserInfo: !resource,\n userStore: sharedStateStore(),\n };\n}\n\nexport function createUserManager(config: LuminaryIdpConfig): UserManager {\n if (manager) return manager;\n manager = new UserManager(userManagerSettings(config));\n return manager;\n}\n\n/**\n * When Experience/Gateway base differs from the IdP issuer origin, fetch OIDC discovery\n * via the gateway (CORS) while keeping `authority` = Logto issuer (JWT `iss`).\n */\nfunction resolveOidcMetadataUrl(config: LuminaryIdpConfig): string | undefined {\n const proxyBase = config.experienceApiBase?.replace(/\\/$/, \"\");\n if (!proxyBase) return undefined;\n try {\n if (new URL(proxyBase).origin === new URL(config.issuer).origin) return undefined;\n } catch {\n return undefined;\n }\n return `${proxyBase}/oidc/.well-known/openid-configuration`;\n}\n\nexport function resetUserManager(): void {\n manager = null;\n}\n\nexport interface SignInOptions {\n returnUrl?: string;\n /**\n * Logto direct sign-in, e.g. `social:google` / `social:github` / `sso:<connectorId>`.\n * Skips the hosted password page and opens the provider immediately.\n */\n directSignIn?: string;\n}\n\nfunction signInArgs(config: LuminaryIdpConfig, options?: SignInOptions | string) {\n const normalized: SignInOptions =\n typeof options === \"string\" ? { returnUrl: options } : (options ?? {});\n const resource = config.audience?.trim();\n const extraQueryParams: Record<string, string> = {};\n if (resource) extraQueryParams.resource = resource;\n if (normalized.directSignIn) extraQueryParams.direct_sign_in = normalized.directSignIn;\n return {\n state: normalized.returnUrl ? { returnUrl: normalized.returnUrl } : undefined,\n extraQueryParams: Object.keys(extraQueryParams).length ? extraQueryParams : undefined,\n };\n}\n\nexport async function signInRedirect(\n config: LuminaryIdpConfig,\n returnUrlOrOptions?: string | SignInOptions,\n): Promise<void> {\n resetUserManager();\n const um = createUserManager(config);\n await um.signinRedirect(signInArgs(config, returnUrlOrOptions));\n}\n\n/**\n * Persist PKCE state (same store as {@link createUserManager}) and return the\n * authorize URL — used by Experience headless bootstrap before navigating to\n * `redirectTo` from `/api/experience/submit`.\n */\nexport async function prepareSignInRequestUrl(\n config: LuminaryIdpConfig,\n returnUrlOrOptions?: string | SignInOptions,\n): Promise<string> {\n resetUserManager();\n // Warm the singleton so callback uses identical settings/stores.\n createUserManager(config);\n const client = new OidcClient(clientSettings(config));\n const args = signInArgs(config, returnUrlOrOptions);\n const request = await client.createSigninRequest({\n state: args.state,\n extraQueryParams: {\n ...(args.extraQueryParams ?? {}),\n prompt: \"login\",\n },\n });\n return request.url;\n}\n\n/**\n * OIDC login in a popup window (not an iframe). Opener keeps SPA state;\n * callback page in the popup must call {@link handleSignInPopupCallback}.\n */\nexport async function signInPopup(\n config: LuminaryIdpConfig,\n returnUrlOrOptions?: string | SignInOptions,\n): Promise<{ session: LuminaryAuthSession; returnUrl?: string }> {\n resetUserManager();\n const um = createUserManager(config);\n const user = await um.signinPopup(signInArgs(config, returnUrlOrOptions));\n const session = toSession(user);\n if (!session.accessToken) {\n throw new Error(\"IdP did not return access_token (check audience / API resource)\");\n }\n assertJwtAccessToken(session.accessToken);\n localStorage.setItem(storageKey(config), session.accessToken);\n const stateReturnUrl =\n typeof user.state === \"object\" && user.state && \"returnUrl\" in user.state\n ? String((user.state as { returnUrl?: string }).returnUrl ?? \"\")\n : undefined;\n return { session, returnUrl: stateReturnUrl || undefined };\n}\n\nexport async function handleSignInCallback(config: LuminaryIdpConfig): Promise<{\n session: LuminaryAuthSession;\n returnUrl?: string;\n}> {\n const um = createUserManager(config);\n const user = await um.signinRedirectCallback();\n const session = toSession(user);\n assertJwtAccessToken(session.accessToken);\n localStorage.setItem(storageKey(config), session.accessToken);\n const returnUrl =\n typeof user.state === \"object\" && user.state && \"returnUrl\" in user.state\n ? String((user.state as { returnUrl?: string }).returnUrl ?? \"\")\n : undefined;\n return { session, returnUrl: returnUrl || undefined };\n}\n\n/**\n * Complete popup OIDC in the popup window. Notifies the opener and closes.\n * Do not run product SSO exchange here — the opener handles that after signInPopup resolves.\n */\nexport async function handleSignInPopupCallback(config: LuminaryIdpConfig): Promise<void> {\n const um = createUserManager(config);\n await um.signinPopupCallback();\n}\n\n/** True when this window is likely an OIDC popup callback. */\nexport function isOidcPopupWindow(): boolean {\n try {\n return Boolean(window.opener && window.opener !== window);\n } catch {\n return false;\n }\n}\n\nexport async function signOutRedirect(config: LuminaryIdpConfig): Promise<void> {\n localStorage.removeItem(storageKey(config));\n const um = createUserManager(config);\n await um.signoutRedirect();\n}\n\nexport function getStoredAccessToken(config: LuminaryIdpConfig): string | null {\n return localStorage.getItem(storageKey(config));\n}\n\nexport function clearStoredSession(config: LuminaryIdpConfig): void {\n localStorage.removeItem(storageKey(config));\n}\n\nfunction toSession(user: User): LuminaryAuthSession {\n return {\n accessToken: user.access_token,\n idToken: user.id_token,\n expiresAt: user.expires_at ? user.expires_at * 1000 : undefined,\n profile: user.profile as Record<string, unknown>,\n };\n}\n\nfunction assertJwtAccessToken(accessToken: string): void {\n if (accessToken.split(\".\").length !== 3) {\n throw new Error(\n \"Received non-JWT access_token. Pass resource (audience) on authorize/token and register the API resource at the IdP.\",\n );\n }\n}\n\nexport async function getCurrentUser(config: LuminaryIdpConfig): Promise<LuminaryAuthSession | null> {\n const um = createUserManager(config);\n const user = await um.getUser();\n if (!user || user.expired) return null;\n return toSession(user);\n}\n","/**\n * Logto Experience API (Headless) client.\n * Prefer same-origin Experience base (SPA proxies /api/experience) so cookies work on HTTP localhost.\n * @see https://docs.logto.io/docs/recipes/customize-token-claims (Experience API recipes)\n */\n\nimport { prepareSignInRequestUrl } from \"./oidc-client\";\nimport type { LuminaryIdpConfig } from \"./types\";\n\nexport type ExperienceIdentifierType = \"email\" | \"username\" | \"phone\";\n\nexport interface ExperiencePasswordSignInInput {\n /** Experience API origin (no trailing slash). Prefer SPA origin when proxied. */\n apiBase: string;\n identifier: string;\n password: string;\n identifierType?: ExperienceIdentifierType;\n /** Required to bootstrap the OIDC interaction cookie before Experience calls. */\n issuer?: string;\n clientId?: string;\n redirectUri?: string;\n audience?: string;\n scopes?: string;\n /** Carried in OIDC state for post-login return (UserManager PKCE). */\n returnUrl?: string;\n}\n\nexport interface ExperiencePasswordSignInResult {\n /** Continue URL from Experience submit (complete OIDC interaction). */\n redirectTo?: string;\n raw?: unknown;\n}\n\nfunction experienceUrl(apiBase: string, path: string): string {\n return `${apiBase.replace(/\\/$/, \"\")}/api/experience${path}`;\n}\n\nasync function experienceFetch<T>(apiBase: string, path: string, init: RequestInit): Promise<T> {\n const res = await fetch(experienceUrl(apiBase, path), {\n credentials: \"include\",\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(init.headers ?? {}),\n },\n });\n const text = await res.text();\n let data: unknown = null;\n if (text) {\n try {\n data = JSON.parse(text) as unknown;\n } catch {\n data = text;\n }\n }\n if (!res.ok) {\n const msg =\n data && typeof data === \"object\" && data !== null && \"message\" in data\n ? String((data as { message: unknown }).message)\n : `Experience API ${res.status}`;\n throw new Error(msg);\n }\n return data as T;\n}\n\nfunction guessIdentifierType(identifier: string): ExperienceIdentifierType {\n if (identifier.includes(\"@\")) return \"email\";\n if (/^\\+?\\d{6,}$/.test(identifier.trim())) return \"phone\";\n return \"username\";\n}\n\n/**\n * Force authorize onto the Experience/SPA origin so Set-Cookie lands on the same\n * host as subsequent `/api/experience` calls (dev proxy strips Domain).\n */\nexport function sameOriginAuthorizeUrl(authorizeUrl: string, apiBase: string): string {\n const u = new URL(authorizeUrl);\n const base = new URL(apiBase);\n if (u.origin === base.origin) return authorizeUrl;\n return `${base.origin}${u.pathname}${u.search}${u.hash}`;\n}\n\n/**\n * Logto only creates the interaction cookie after an authorize request.\n * Use UserManager.createSigninRequest so PKCE state matches `/auth/callback`,\n * then load authorize via the SPA proxy (same-origin cookies).\n */\nasync function bootstrapOidcInteraction(input: ExperiencePasswordSignInInput): Promise<void> {\n if (!input.issuer || !input.clientId || !input.redirectUri) return;\n if (typeof document === \"undefined\") return;\n\n const config: LuminaryIdpConfig = {\n issuer: input.issuer,\n clientId: input.clientId,\n redirectUri: input.redirectUri,\n audience: input.audience,\n scopes: input.scopes,\n experienceApiBase: input.apiBase,\n };\n\n const signinUrl = await prepareSignInRequestUrl(config, {\n returnUrl: input.returnUrl,\n });\n const authorizeUrl = sameOriginAuthorizeUrl(signinUrl, input.apiBase);\n\n await new Promise<void>((resolve) => {\n const iframe = document.createElement(\"iframe\");\n iframe.setAttribute(\"aria-hidden\", \"true\");\n iframe.tabIndex = -1;\n iframe.style.cssText = \"position:absolute;width:0;height:0;border:0;visibility:hidden\";\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n iframe.remove();\n resolve();\n };\n iframe.addEventListener(\"load\", () => {\n window.setTimeout(finish, 400);\n });\n iframe.src = authorizeUrl;\n document.body.appendChild(iframe);\n window.setTimeout(finish, 2500);\n });\n}\n\n/**\n * Headless password sign-in via Logto Experience API.\n * Requires an OIDC interaction cookie (see {@link bootstrapOidcInteraction}) and\n * same-site Experience calls (SPA proxy or Auth Gateway on the SPA origin).\n *\n * On success, follow {@link ExperiencePasswordSignInResult.redirectTo} in the same\n * window — that URL completes the PKCE round-trip started by createSigninRequest.\n * Do not start a second authorize (that shows Logto `/sign-in` again).\n *\n * Tries the guessed identifier type first, then the alternate email/username so\n * users can sign in with either when both methods are enabled on the IdP.\n */\nexport async function experiencePasswordSignIn(\n input: ExperiencePasswordSignInInput,\n): Promise<ExperiencePasswordSignInResult> {\n const { apiBase, identifier, password } = input;\n await bootstrapOidcInteraction(input);\n\n const primary = input.identifierType ?? guessIdentifierType(identifier);\n const alternates: ExperienceIdentifierType[] =\n primary === \"phone\"\n ? [primary]\n : primary === \"email\"\n ? [\"email\", \"username\"]\n : [\"username\", \"email\"];\n\n let lastError: Error | undefined;\n for (const identifierType of alternates) {\n try {\n await experienceFetch(apiBase, \"\", {\n method: \"PUT\",\n body: JSON.stringify({ interactionEvent: \"SignIn\" }),\n });\n\n const verified = await experienceFetch<{ verificationId?: string }>(\n apiBase,\n \"/verification/password\",\n {\n method: \"POST\",\n body: JSON.stringify({\n identifier: { type: identifierType, value: identifier },\n password,\n }),\n },\n );\n\n const verificationId = verified?.verificationId;\n if (!verificationId) {\n throw new Error(\"Experience API did not return verificationId\");\n }\n\n await experienceFetch(apiBase, \"/identification\", {\n method: \"POST\",\n body: JSON.stringify({ verificationId }),\n });\n\n const submitted = await experienceFetch<{ redirectTo?: string }>(apiBase, \"/submit\", {\n method: \"POST\",\n body: JSON.stringify({}),\n });\n\n return { redirectTo: submitted?.redirectTo, raw: submitted };\n } catch (e) {\n lastError = e instanceof Error ? e : new Error(String(e));\n }\n }\n throw lastError ?? new Error(\"Experience password sign-in failed\");\n}\n\nexport interface ExperienceSocialConnector {\n id: string;\n target: string;\n name: string;\n logo?: string;\n}\n\n/**\n * Public Logto sign-in experience (no auth). Returns enabled social connectors\n * in SIE order — use for Headless social buttons (google / github / x / …).\n */\nexport async function fetchSocialConnectors(input: {\n /** Same origin as Experience / IdP (e.g. SPA proxy or http://localhost:3001). */\n apiBase: string;\n appId?: string;\n}): Promise<ExperienceSocialConnector[]> {\n const url = new URL(`${input.apiBase.replace(/\\/$/, \"\")}/api/.well-known/sign-in-exp`);\n if (input.appId?.trim()) url.searchParams.set(\"appId\", input.appId.trim());\n const res = await fetch(url.toString(), {\n // Public metadata — omit cookies so browsers do not require credentialed CORS.\n credentials: \"omit\",\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) {\n throw new Error(`sign-in-exp ${res.status}`);\n }\n const data = (await res.json()) as {\n socialConnectors?: Array<{\n id?: string;\n target?: string;\n name?: string | Record<string, string>;\n logo?: string;\n }>;\n };\n return (data.socialConnectors ?? [])\n .filter((c): c is { id: string; target: string; name?: string | Record<string, string>; logo?: string } =>\n Boolean(c?.id && c?.target),\n )\n .map((c) => ({\n id: c.id,\n target: c.target,\n name: localizeName(c.name) || titleCase(c.target),\n logo: c.logo,\n }));\n}\n\nfunction localizeName(name: string | Record<string, string> | undefined): string {\n if (!name) return \"\";\n if (typeof name === \"string\") return name;\n return name[\"zh-CN\"] || name.en || Object.values(name)[0] || \"\";\n}\n\nfunction titleCase(target: string): string {\n if (!target) return \"\";\n return target.charAt(0).toUpperCase() + target.slice(1);\n}\n","/**\n * AuthGate — single-flight 401 recovery with optional token refresh + reauth UI.\n * Products wire tryRefresh / onReauthRequired; API clients call handleUnauthorized + waitIfBlocked.\n */\n\nexport type AuthGatePhase = \"idle\" | \"refreshing\" | \"reauth\";\n\nexport type UnauthorizedDisposition = \"retry\" | \"fail\";\n\nexport interface AuthGateSnapshot {\n phase: AuthGatePhase;\n /** True while refresh or interactive reauth is in flight. */\n blocked: boolean;\n lastError?: string;\n}\n\nexport interface AuthGateConfig {\n /**\n * Attempt silent product-token (or OIDC) refresh before showing reauth UI.\n * Return true if a new session was established.\n */\n tryRefresh?: () => Promise<boolean>;\n /** Called once when interactive reauth is required (open modal / popup). */\n onReauthRequired?: () => void;\n /** Called when reauth succeeds or is cancelled (phase back to idle). */\n onSettled?: (ok: boolean) => void;\n}\n\ntype Waiter = {\n resolve: (disposition: UnauthorizedDisposition) => void;\n};\n\nclass AuthGateCoordinator {\n private phase: AuthGatePhase = \"idle\";\n private lastError?: string;\n /** Cached for useSyncExternalStore — must keep referential equality when unchanged. */\n private snapshot: AuthGateSnapshot = { phase: \"idle\", blocked: false };\n private config: AuthGateConfig = {};\n private flight: Promise<UnauthorizedDisposition> | null = null;\n private reauthWaiters: Waiter[] = [];\n private listeners = new Set<() => void>();\n\n configure(config: AuthGateConfig): void {\n this.config = { ...this.config, ...config };\n }\n\n getSnapshot = (): AuthGateSnapshot => this.snapshot;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n private emit(): void {\n for (const listener of this.listeners) listener();\n }\n\n private setPhase(phase: AuthGatePhase, lastError?: string): void {\n if (this.phase === phase && this.lastError === lastError) return;\n this.phase = phase;\n this.lastError = lastError;\n this.snapshot = {\n phase,\n blocked: phase !== \"idle\",\n lastError,\n };\n this.emit();\n }\n\n /** Await while a recovery is in flight (pause outbound API traffic). */\n async waitIfBlocked(): Promise<void> {\n if (!this.flight) return;\n await this.flight;\n }\n\n /**\n * Single-flight 401 handler.\n * Concurrent callers share one recovery; all receive the same disposition.\n */\n handleUnauthorized(errorMessage?: string): Promise<UnauthorizedDisposition> {\n if (this.flight) return this.flight;\n this.flight = this.runRecovery(errorMessage).finally(() => {\n this.flight = null;\n });\n return this.flight;\n }\n\n /** Open reauth UI without a preceding 401 (cold start / deep link). */\n requestReauth(errorMessage?: string): Promise<UnauthorizedDisposition> {\n return this.handleUnauthorized(errorMessage);\n }\n\n /** Product calls after popup / Headless login restored the session. */\n completeReauth(): void {\n if (this.phase !== \"reauth\") return;\n const waiters = this.reauthWaiters.splice(0, this.reauthWaiters.length);\n this.setPhase(\"idle\");\n this.config.onSettled?.(true);\n for (const w of waiters) w.resolve(\"retry\");\n }\n\n /** User dismissed reauth; fail queued recovery waiters. */\n cancelReauth(errorMessage?: string): void {\n if (this.phase !== \"reauth\") return;\n const waiters = this.reauthWaiters.splice(0, this.reauthWaiters.length);\n this.setPhase(\"idle\", errorMessage);\n this.config.onSettled?.(false);\n for (const w of waiters) w.resolve(\"fail\");\n }\n\n private async runRecovery(errorMessage?: string): Promise<UnauthorizedDisposition> {\n this.lastError = errorMessage;\n\n if (this.config.tryRefresh) {\n this.setPhase(\"refreshing\", errorMessage);\n try {\n const ok = await this.config.tryRefresh();\n if (ok) {\n this.setPhase(\"idle\");\n this.config.onSettled?.(true);\n return \"retry\";\n }\n } catch (e) {\n this.lastError = e instanceof Error ? e.message : String(e);\n }\n }\n\n this.setPhase(\"reauth\", this.lastError);\n this.config.onReauthRequired?.();\n\n return new Promise<UnauthorizedDisposition>((resolve) => {\n this.reauthWaiters.push({ resolve });\n });\n }\n}\n\n/** Process-wide gate (one per SPA bundle). */\nexport const authGate = new AuthGateCoordinator();\n\n/**\n * Run an async request; on 401, recover via AuthGate and retry once.\n * `isUnauthorized` defaults to checking `status === 401` or `statusCode === 401`.\n */\nexport async function withAuthGateRetry<T>(\n execute: () => Promise<T>,\n options?: {\n isUnauthorized?: (error: unknown) => boolean;\n /** Skip gate (e.g. refresh / sso / login endpoints). */\n bypass?: boolean;\n },\n): Promise<T> {\n if (options?.bypass) return execute();\n\n await authGate.waitIfBlocked();\n\n try {\n return await execute();\n } catch (error) {\n if (!(options?.isUnauthorized ?? defaultIsUnauthorized)(error)) throw error;\n const disposition = await authGate.handleUnauthorized(messageOf(error));\n if (disposition !== \"retry\") throw error;\n return execute();\n }\n}\n\nfunction defaultIsUnauthorized(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const e = error as { status?: number; statusCode?: number; response?: { status?: number } };\n return e.status === 401 || e.statusCode === 401 || e.response?.status === 401;\n}\n\nfunction messageOf(error: unknown): string | undefined {\n if (error instanceof Error) return error.message;\n if (error && typeof error === \"object\" && \"message\" in error) {\n const m = (error as { message?: unknown }).message;\n return typeof m === \"string\" ? m : undefined;\n }\n return undefined;\n}\n","import { createContext, useCallback, useContext, useEffect, useMemo, useState } from \"react\";\nimport {\n clearStoredSession,\n getCurrentUser,\n getStoredAccessToken,\n handleSignInCallback,\n signInPopup,\n signInRedirect,\n signOutRedirect,\n} from \"./oidc-client\";\nimport { isIdpConfigured, readIdpConfigFromEnv, type LuminaryAuthSession, type LuminaryIdpConfig } from \"./types\";\n\ninterface LuminaryAuthContextValue {\n configured: boolean;\n session: LuminaryAuthSession | null;\n accessToken: string | null;\n loading: boolean;\n login: (returnUrl?: string) => Promise<void>;\n /** Popup OIDC — keeps the opener SPA mounted. */\n loginPopup: (returnUrl?: string) => Promise<LuminaryAuthSession>;\n logout: () => Promise<void>;\n completeCallback: () => Promise<{ returnUrl?: string }>;\n refreshSession: () => Promise<void>;\n}\n\nconst LuminaryAuthContext = createContext<LuminaryAuthContextValue | null>(null);\n\nexport interface LuminaryAuthProviderProps {\n config?: Partial<LuminaryIdpConfig>;\n children: React.ReactNode;\n}\n\nexport function LuminaryAuthProvider({ config: configProp, children }: LuminaryAuthProviderProps) {\n const config = useMemo(() => configProp ?? {}, [configProp]);\n const configured = isIdpConfigured(config);\n const [session, setSession] = useState<LuminaryAuthSession | null>(null);\n const [loading, setLoading] = useState(configured);\n\n const refreshSession = useCallback(async () => {\n if (!configured) {\n setSession(null);\n setLoading(false);\n return;\n }\n setLoading(true);\n try {\n const current = await getCurrentUser(config);\n setSession(current);\n } catch {\n setSession(null);\n } finally {\n setLoading(false);\n }\n }, [config, configured]);\n\n useEffect(() => {\n void refreshSession();\n }, [refreshSession]);\n\n const login = useCallback(\n async (returnUrl?: string) => {\n if (!configured) throw new Error(\"IdP not configured\");\n await signInRedirect(config, returnUrl);\n },\n [config, configured],\n );\n\n const loginPopup = useCallback(\n async (returnUrl?: string) => {\n if (!configured) throw new Error(\"IdP not configured\");\n const { session: next } = await signInPopup(config, returnUrl);\n setSession(next);\n return next;\n },\n [config, configured],\n );\n\n const logout = useCallback(async () => {\n if (!configured) {\n clearStoredSession(config as LuminaryIdpConfig);\n setSession(null);\n return;\n }\n setSession(null);\n await signOutRedirect(config);\n }, [config, configured]);\n\n const completeCallback = useCallback(async () => {\n if (!configured) throw new Error(\"IdP not configured\");\n const { session: next, returnUrl } = await handleSignInCallback(config);\n setSession(next);\n return { returnUrl };\n }, [config, configured]);\n\n const value = useMemo<LuminaryAuthContextValue>(\n () => ({\n configured,\n session,\n accessToken: session?.accessToken ?? (configured ? getStoredAccessToken(config) : null),\n loading,\n login,\n loginPopup,\n logout,\n completeCallback,\n refreshSession,\n }),\n [configured, session, loading, login, loginPopup, logout, completeCallback, refreshSession, config],\n );\n\n return <LuminaryAuthContext.Provider value={value}>{children}</LuminaryAuthContext.Provider>;\n}\n\nexport function useLuminaryAuth(): LuminaryAuthContextValue {\n const ctx = useContext(LuminaryAuthContext);\n if (!ctx) throw new Error(\"useLuminaryAuth must be used within LuminaryAuthProvider\");\n return ctx;\n}\n\nexport { isIdpConfigured, readIdpConfigFromEnv };\nexport type { LuminaryAuthSession, LuminaryIdpConfig };\n",".panel {\n --lw-auth-theme: #3a84ff;\n --lw-auth-theme-deep: color-mix(in srgb, var(--lw-auth-theme) 72%, #000);\n width: min(100%, 400px);\n padding: 28px 28px 22px;\n border-radius: 16px;\n background: rgba(255, 255, 255, 0.96);\n color: #14212b;\n box-shadow: 0 24px 64px rgba(15, 23, 42, 0.28);\n font-family: \"Segoe UI\", \"PingFang SC\", \"Noto Sans SC\", sans-serif;\n}\n\n.brand {\n display: flex;\n gap: 14px;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.logo {\n border-radius: 12px;\n display: block;\n}\n\n.product {\n margin: 0;\n font-size: 13px;\n font-weight: 650;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--lw-auth-theme);\n}\n\n.title {\n margin: 2px 0 0;\n font-size: 22px;\n font-weight: 700;\n line-height: 1.25;\n}\n\n.subtitle {\n margin: 0 0 18px;\n font-size: 14px;\n line-height: 1.5;\n color: #4b5c68;\n}\n\n.form {\n display: grid;\n gap: 10px;\n}\n\n.socialStack {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.input {\n width: 100%;\n box-sizing: border-box;\n border: 1px solid #c9d5de;\n border-radius: 10px;\n padding: 10px 12px;\n font-size: 14px;\n outline: none;\n background: #f7fafc;\n}\n.input:focus {\n border-color: var(--lw-auth-theme);\n}\n.input:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.passwordField {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.passwordInput {\n padding-right: 42px;\n}\n\n.passwordToggle {\n position: absolute;\n right: 4px;\n top: 50%;\n transform: translateY(-50%);\n z-index: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 4px;\n padding: 0;\n color: #5a6b76;\n background: transparent;\n cursor: pointer;\n}\n.passwordToggle:hover:not(:disabled) {\n color: var(--lw-auth-theme);\n background: color-mix(in srgb, var(--lw-auth-theme) 12%, transparent);\n}\n.passwordToggle:focus-visible {\n outline: 2px solid var(--lw-auth-theme);\n outline-offset: 1px;\n}\n.passwordToggle:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.primaryBtn {\n border: none;\n border-radius: 10px;\n padding: 11px 14px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: #fff;\n background: linear-gradient(135deg, var(--lw-auth-theme) 0%, var(--lw-auth-theme-deep) 100%);\n}\n.primaryBtn:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.socialBtn {\n flex: 1 1 calc(50% - 5px);\n min-width: min(140px, 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n border: 1px solid #b7c9d4;\n border-radius: 10px;\n padding: 11px 10px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: #14212b;\n background: #fff;\n}\n.socialBtn:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.socialLogo {\n flex-shrink: 0;\n display: block;\n}\n\n.logoFallback {\n width: 18px;\n height: 18px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--lw-auth-theme) 14%, #fff);\n color: var(--lw-auth-theme-deep);\n font-size: 11px;\n font-weight: 700;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.cancelBtn {\n margin-top: 10px;\n width: 100%;\n border: none;\n background: transparent;\n color: #5a6b76;\n font-size: 13px;\n cursor: pointer;\n padding: 8px;\n}\n.cancelBtn:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.divider {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 14px 0;\n color: #90a0ab;\n}\n\n.dividerLine {\n flex: 1;\n height: 1px;\n background: #d5e0e7;\n}\n\n.dividerText {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.hint {\n margin: 10px 0 0;\n font-size: 12px;\n color: #6b7c87;\n line-height: 1.45;\n}\n\n.error {\n margin: 12px 0 0;\n font-size: 13px;\n color: #b42318;\n line-height: 1.4;\n}\n\n.footer {\n margin-top: 18px;\n padding-top: 12px;\n border-top: 1px solid #e4ebf0;\n font-size: 12px;\n color: #6b7c87;\n display: flex;\n gap: 8px;\n justify-content: center;\n}\n/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkhlYWRsZXNzTG9naW5QYW5lbC5tb2R1bGUuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFrQkE7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBLGVBVFU7RUFVVjtFQUNBLE9BekJJO0VBMEJKO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0EsT0E3RE07OztBQWdFUjtFQUNFO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0EsZUFsRVU7RUFtRVY7RUFDQTtFQUNBO0VBQ0EsWUEzRVE7O0FBNkVSO0VBQ0U7O0FBR0Y7RUFDRTtFQUNBOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0EsZUF2R1U7RUF3R1Y7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBOztBQUdGO0VBQ0U7RUFDQTs7QUFHRjtFQUNFO0VBQ0E7OztBQUlKO0VBQ0U7RUFDQSxlQWhJVTtFQWlJVjtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0EsZUF0SlU7RUF1SlY7RUFDQTtFQUNBO0VBQ0E7RUFDQSxPQTFLSTtFQTJLSjs7QUFFQTtFQUNFO0VBQ0E7OztBQUlKO0VBQ0U7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0EsZUEzS1U7RUE0S1Y7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7RUFDQTs7O0FBSUo7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBLE9BbE5ROzs7QUFxTlY7RUFDRTtFQUNBO0VBQ0EsWUF6Tks7OztBQTROUDtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0EsT0EzT0s7RUE0T0w7OztBQUdGO0VBQ0U7RUFDQTtFQUNBLE9BeE9PO0VBeU9QOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0EsT0EzUEs7RUE0UEw7RUFDQTtFQUNBIiwic291cmNlc0NvbnRlbnQiOlsiJGluazogIzE0MjEyYjtcbiRtdXRlZDogIzRiNWM2ODtcbiRoaW50OiAjNmI3Yzg3O1xuJGJyYW5kOiAjM2Q2ZjhmO1xuJGJyYW5kLWRlZXA6ICMxNTQ4NWM7XG4kYnJhbmQtbWlkOiAjMWY2ZjhiO1xuJGJvcmRlcjogI2M5ZDVkZTtcbiRib3JkZXItc29mdDogI2I3YzlkNDtcbiRsaW5lOiAjZDVlMGU3O1xuJGRpdmlkZXI6ICM5MGEwYWI7XG4kc3VyZmFjZTogI2Y3ZmFmYztcbiRmYWxsYmFjay1iZzogI2U4ZWVmMjtcbiRkYW5nZXI6ICNiNDIzMTg7XG4kZm9vdGVyLWxpbmU6ICNlNGViZjA7XG4kcmFkaXVzLWxnOiAxNnB4O1xuJHJhZGl1cy1tZDogMTBweDtcbiRyYWRpdXMtc206IDRweDtcblxuLnBhbmVsIHtcbiAgLS1sdy1hdXRoLXRoZW1lOiAjM2E4NGZmO1xuICAtLWx3LWF1dGgtdGhlbWUtZGVlcDogY29sb3ItbWl4KGluIHNyZ2IsIHZhcigtLWx3LWF1dGgtdGhlbWUpIDcyJSwgIzAwMCk7XG4gIHdpZHRoOiBtaW4oMTAwJSwgNDAwcHgpO1xuICBwYWRkaW5nOiAyOHB4IDI4cHggMjJweDtcbiAgYm9yZGVyLXJhZGl1czogJHJhZGl1cy1sZztcbiAgYmFja2dyb3VuZDogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjk2KTtcbiAgY29sb3I6ICRpbms7XG4gIGJveC1zaGFkb3c6IDAgMjRweCA2NHB4IHJnYmEoMTUsIDIzLCA0MiwgMC4yOCk7XG4gIGZvbnQtZmFtaWx5OiBcIlNlZ29lIFVJXCIsIFwiUGluZ0ZhbmcgU0NcIiwgXCJOb3RvIFNhbnMgU0NcIiwgc2Fucy1zZXJpZjtcbn1cblxuLmJyYW5kIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZ2FwOiAxNHB4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBtYXJnaW4tYm90dG9tOiAxMnB4O1xufVxuXG4ubG9nbyB7XG4gIGJvcmRlci1yYWRpdXM6IDEycHg7XG4gIGRpc3BsYXk6IGJsb2NrO1xufVxuXG4ucHJvZHVjdCB7XG4gIG1hcmdpbjogMDtcbiAgZm9udC1zaXplOiAxM3B4O1xuICBmb250LXdlaWdodDogNjUwO1xuICBsZXR0ZXItc3BhY2luZzogMC4wNGVtO1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICBjb2xvcjogdmFyKC0tbHctYXV0aC10aGVtZSk7XG59XG5cbi50aXRsZSB7XG4gIG1hcmdpbjogMnB4IDAgMDtcbiAgZm9udC1zaXplOiAyMnB4O1xuICBmb250LXdlaWdodDogNzAwO1xuICBsaW5lLWhlaWdodDogMS4yNTtcbn1cblxuLnN1YnRpdGxlIHtcbiAgbWFyZ2luOiAwIDAgMThweDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBsaW5lLWhlaWdodDogMS41O1xuICBjb2xvcjogJG11dGVkO1xufVxuXG4uZm9ybSB7XG4gIGRpc3BsYXk6IGdyaWQ7XG4gIGdhcDogMTBweDtcbn1cblxuLnNvY2lhbFN0YWNrIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC13cmFwOiB3cmFwO1xuICBnYXA6IDEwcHg7XG4gIGZvbnQtc2l6ZTogMTJweDtcbn1cblxuLmlucHV0IHtcbiAgd2lkdGg6IDEwMCU7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGJvcmRlcjogMXB4IHNvbGlkICRib3JkZXI7XG4gIGJvcmRlci1yYWRpdXM6ICRyYWRpdXMtbWQ7XG4gIHBhZGRpbmc6IDEwcHggMTJweDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBvdXRsaW5lOiBub25lO1xuICBiYWNrZ3JvdW5kOiAkc3VyZmFjZTtcblxuICAmOmZvY3VzIHtcbiAgICBib3JkZXItY29sb3I6IHZhcigtLWx3LWF1dGgtdGhlbWUpO1xuICB9XG5cbiAgJjpkaXNhYmxlZCB7XG4gICAgb3BhY2l0eTogMC42NTtcbiAgICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xuICB9XG59XG5cbi5wYXNzd29yZEZpZWxkIHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xufVxuXG4ucGFzc3dvcmRJbnB1dCB7XG4gIHBhZGRpbmctcmlnaHQ6IDQycHg7XG59XG5cbi5wYXNzd29yZFRvZ2dsZSB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgcmlnaHQ6IDRweDtcbiAgdG9wOiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcbiAgei1pbmRleDogMTtcbiAgZGlzcGxheTogaW5saW5lLWZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICB3aWR0aDogMzZweDtcbiAgaGVpZ2h0OiAzNnB4O1xuICBib3JkZXI6IG5vbmU7XG4gIGJvcmRlci1yYWRpdXM6ICRyYWRpdXMtc207XG4gIHBhZGRpbmc6IDA7XG4gIGNvbG9yOiAjNWE2Yjc2O1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuXG4gICY6aG92ZXI6bm90KDpkaXNhYmxlZCkge1xuICAgIGNvbG9yOiB2YXIoLS1sdy1hdXRoLXRoZW1lKTtcbiAgICBiYWNrZ3JvdW5kOiBjb2xvci1taXgoaW4gc3JnYiwgdmFyKC0tbHctYXV0aC10aGVtZSkgMTIlLCB0cmFuc3BhcmVudCk7XG4gIH1cblxuICAmOmZvY3VzLXZpc2libGUge1xuICAgIG91dGxpbmU6IDJweCBzb2xpZCB2YXIoLS1sdy1hdXRoLXRoZW1lKTtcbiAgICBvdXRsaW5lLW9mZnNldDogMXB4O1xuICB9XG5cbiAgJjpkaXNhYmxlZCB7XG4gICAgb3BhY2l0eTogMC42NTtcbiAgICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xuICB9XG59XG5cbi5wcmltYXJ5QnRuIHtcbiAgYm9yZGVyOiBub25lO1xuICBib3JkZXItcmFkaXVzOiAkcmFkaXVzLW1kO1xuICBwYWRkaW5nOiAxMXB4IDE0cHg7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgZm9udC13ZWlnaHQ6IDY1MDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBjb2xvcjogI2ZmZjtcbiAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDEzNWRlZywgdmFyKC0tbHctYXV0aC10aGVtZSkgMCUsIHZhcigtLWx3LWF1dGgtdGhlbWUtZGVlcCkgMTAwJSk7XG5cbiAgJjpkaXNhYmxlZCB7XG4gICAgb3BhY2l0eTogMC42NTtcbiAgICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xuICB9XG59XG5cbi5zb2NpYWxCdG4ge1xuICBmbGV4OiAxIDEgY2FsYyg1MCUgLSA1cHgpO1xuICBtaW4td2lkdGg6IG1pbigxNDBweCwgMTAwJSk7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBnYXA6IDhweDtcbiAgYm9yZGVyOiAxcHggc29saWQgJGJvcmRlci1zb2Z0O1xuICBib3JkZXItcmFkaXVzOiAkcmFkaXVzLW1kO1xuICBwYWRkaW5nOiAxMXB4IDEwcHg7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgZm9udC13ZWlnaHQ6IDY1MDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBjb2xvcjogJGluaztcbiAgYmFja2dyb3VuZDogI2ZmZjtcblxuICAmOmRpc2FibGVkIHtcbiAgICBvcGFjaXR5OiAwLjY1O1xuICAgIGN1cnNvcjogbm90LWFsbG93ZWQ7XG4gIH1cbn1cblxuLnNvY2lhbExvZ28ge1xuICBmbGV4LXNocmluazogMDtcbiAgZGlzcGxheTogYmxvY2s7XG59XG5cbi5sb2dvRmFsbGJhY2sge1xuICB3aWR0aDogMThweDtcbiAgaGVpZ2h0OiAxOHB4O1xuICBib3JkZXItcmFkaXVzOiAkcmFkaXVzLXNtO1xuICBiYWNrZ3JvdW5kOiBjb2xvci1taXgoaW4gc3JnYiwgdmFyKC0tbHctYXV0aC10aGVtZSkgMTQlLCAjZmZmKTtcbiAgY29sb3I6IHZhcigtLWx3LWF1dGgtdGhlbWUtZGVlcCk7XG4gIGZvbnQtc2l6ZTogMTFweDtcbiAgZm9udC13ZWlnaHQ6IDcwMDtcbiAgZGlzcGxheTogaW5saW5lLWZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBmbGV4LXNocmluazogMDtcbn1cblxuLmNhbmNlbEJ0biB7XG4gIG1hcmdpbi10b3A6IDEwcHg7XG4gIHdpZHRoOiAxMDAlO1xuICBib3JkZXI6IG5vbmU7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICBjb2xvcjogIzVhNmI3NjtcbiAgZm9udC1zaXplOiAxM3B4O1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIHBhZGRpbmc6IDhweDtcblxuICAmOmRpc2FibGVkIHtcbiAgICBvcGFjaXR5OiAwLjY1O1xuICAgIGN1cnNvcjogbm90LWFsbG93ZWQ7XG4gIH1cbn1cblxuLmRpdmlkZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDEwcHg7XG4gIG1hcmdpbjogMTRweCAwO1xuICBjb2xvcjogJGRpdmlkZXI7XG59XG5cbi5kaXZpZGVyTGluZSB7XG4gIGZsZXg6IDE7XG4gIGhlaWdodDogMXB4O1xuICBiYWNrZ3JvdW5kOiAkbGluZTtcbn1cblxuLmRpdmlkZXJUZXh0IHtcbiAgZm9udC1zaXplOiAxMnB4O1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICBsZXR0ZXItc3BhY2luZzogMC4wOGVtO1xufVxuXG4uaGludCB7XG4gIG1hcmdpbjogMTBweCAwIDA7XG4gIGZvbnQtc2l6ZTogMTJweDtcbiAgY29sb3I6ICRoaW50O1xuICBsaW5lLWhlaWdodDogMS40NTtcbn1cblxuLmVycm9yIHtcbiAgbWFyZ2luOiAxMnB4IDAgMDtcbiAgZm9udC1zaXplOiAxM3B4O1xuICBjb2xvcjogJGRhbmdlcjtcbiAgbGluZS1oZWlnaHQ6IDEuNDtcbn1cblxuLmZvb3RlciB7XG4gIG1hcmdpbi10b3A6IDE4cHg7XG4gIHBhZGRpbmctdG9wOiAxMnB4O1xuICBib3JkZXItdG9wOiAxcHggc29saWQgJGZvb3Rlci1saW5lO1xuICBmb250LXNpemU6IDEycHg7XG4gIGNvbG9yOiAkaGludDtcbiAgZGlzcGxheTogZmxleDtcbiAgZ2FwOiA4cHg7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xufVxuIl19 */","import { useEffect, useState, type CSSProperties, type FormEvent, type ReactNode } from \"react\";\nimport { experiencePasswordSignIn, fetchSocialConnectors, type ExperienceSocialConnector } from \"./experience-client\";\nimport { signInPopup, signInRedirect } from \"./oidc-client\";\nimport { isIdpConfigured, type LuminaryAuthSession, type LuminaryIdpConfig } from \"./types\";\nimport styles from \"./HeadlessLoginPanel.module.scss\";\n\n/** @deprecated Prefer dynamic connectors from IdP; kept for prop typing. */\nexport type SocialProviderTarget = string;\n\nexport interface HeadlessLoginLabels {\n title?: string;\n subtitle?: string;\n identifierPlaceholder?: string;\n passwordPlaceholder?: string;\n submitPassword?: string;\n /** @deprecated Use social buttons; kept for backward-compatible label overrides. */\n submitSso?: string;\n submitGoogle?: string;\n submitGithub?: string;\n socialDivider?: string;\n hint?: string;\n cancel?: string;\n experienceUnavailable?: string;\n showPassword?: string;\n hidePassword?: string;\n}\n\nexport interface HeadlessLoginPanelProps {\n config: Partial<LuminaryIdpConfig>;\n /** Product display name shown as brand signal */\n productName: string;\n logoSrc?: string;\n labels?: HeadlessLoginLabels;\n returnUrl?: string;\n /** Prefer popup (default) for reauth; use redirect for full-page login. */\n mode?: \"popup\" | \"redirect\";\n /**\n * Show Experience social connectors (Google / GitHub / …).\n * Default `true`. Set `false` for admin / internal consoles that only allow\n * password (or enterprise SSO via IdP) — hides divider + social buttons and\n * skips fetching connectors.\n * Equivalent to `socialProviders={[]}` when false.\n */\n showSocialConnectors?: boolean;\n /**\n * Social providers (when `showSocialConnectors` is not `false`):\n * - omit / `\"auto\"` — load enabled connectors from IdP (google, github, x, …)\n * - `string[]` — only these targets (still prefers IdP logos/names when available)\n * - `[]` — hide social buttons\n */\n socialProviders?: \"auto\" | SocialProviderTarget[];\n showCancel?: boolean;\n onCancel?: () => void;\n /**\n * Called after OIDC session is obtained (popup) or before redirect navigation.\n * Products typically exchange OIDC access token → product JWT here.\n */\n onOidcSession?: (session: LuminaryAuthSession, returnUrl?: string) => Promise<void> | void;\n /** When Experience returns redirectTo, open it (default: same-tab assign). */\n onExperienceRedirect?: (redirectTo: string) => void;\n footer?: ReactNode;\n className?: string;\n style?: CSSProperties;\n /**\n * Brand accent for primary CTA / focus / product label.\n * Defaults to `#3a84ff` (DataLuminary / BlockyEdu).\n */\n themeColor?: string;\n}\n\n/** Shared default accent for product login panels. */\nexport const DEFAULT_LOGIN_THEME_COLOR = \"#3a84ff\";\n\nconst defaults: Required<HeadlessLoginLabels> = {\n title: \"Sign in\",\n subtitle: \"Use your LuminaryWorks unified account\",\n identifierPlaceholder: \"Email or username\",\n passwordPlaceholder: \"Password\",\n submitPassword: \"Sign in with password\",\n submitSso: \"Continue with unified account\",\n submitGoogle: \"Google\",\n submitGithub: \"GitHub\",\n socialDivider: \"or\",\n hint: \"Social providers open directly. Password uses your LuminaryWorks account.\",\n cancel: \"Cancel\",\n experienceUnavailable: \"Password sign-in is unavailable; use a social provider instead.\",\n showPassword: \"Show password\",\n hidePassword: \"Hide password\",\n};\n\nfunction resolveSieBase(config: Partial<LuminaryIdpConfig>): string | undefined {\n // Prefer same-origin Experience base (SPA proxies /api/.well-known) to avoid\n // cross-port CORS on local Logto. Fall back to issuer origin only when needed.\n const explicit = config.experienceApiBase?.trim();\n if (explicit) return explicit.replace(/\\/$/, \"\");\n if (config.issuer) {\n try {\n return new URL(config.issuer).origin;\n } catch {\n /* fall through */\n }\n }\n return undefined;\n}\n\nfunction labelFor(connector: ExperienceSocialConnector, labels: Required<HeadlessLoginLabels>): string {\n if (connector.target === \"google\" && labels.submitGoogle) return labels.submitGoogle;\n if (connector.target === \"github\" && labels.submitGithub) return labels.submitGithub;\n return connector.name;\n}\n\nfunction cx(...parts: Array<string | undefined | false>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport function HeadlessLoginPanel({\n config,\n productName,\n logoSrc,\n labels: labelsProp,\n returnUrl,\n mode = \"popup\",\n showSocialConnectors = true,\n socialProviders = \"auto\",\n showCancel,\n onCancel,\n onOidcSession,\n onExperienceRedirect,\n footer,\n className,\n style,\n themeColor = DEFAULT_LOGIN_THEME_COLOR,\n}: HeadlessLoginPanelProps) {\n const labels = { ...defaults, ...labelsProp };\n const configured = isIdpConfigured(config);\n const [identifier, setIdentifier] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [passwordVisible, setPasswordVisible] = useState(false);\n const panelStyle: CSSProperties = {\n ...style,\n [\"--lw-auth-theme\" as string]: themeColor || DEFAULT_LOGIN_THEME_COLOR,\n };\n const [loading, setLoading] = useState<\"password\" | string | null>(null);\n const [error, setError] = useState(\"\");\n const [connectors, setConnectors] = useState<ExperienceSocialConnector[]>([]);\n const socialEnabled =\n showSocialConnectors !== false &&\n !(Array.isArray(socialProviders) && socialProviders.length === 0);\n\n // Browser back from IdP restores bfcache with loading still set → \"…\".\n useEffect(() => {\n const resetBusy = () => setLoading(null);\n window.addEventListener(\"pageshow\", resetBusy);\n window.addEventListener(\"popstate\", resetBusy);\n return () => {\n window.removeEventListener(\"pageshow\", resetBusy);\n window.removeEventListener(\"popstate\", resetBusy);\n };\n }, []);\n\n useEffect(() => {\n if (!socialEnabled) {\n setConnectors([]);\n return;\n }\n let cancelled = false;\n const sieBase = resolveSieBase(config);\n const allowlist =\n socialProviders === \"auto\" || socialProviders === undefined\n ? null\n : new Set(socialProviders.map((t) => t.toLowerCase()));\n\n const apply = (list: ExperienceSocialConnector[]) => {\n const filtered = allowlist\n ? list.filter((c) => allowlist.has(c.target.toLowerCase()))\n : list;\n if (!cancelled) setConnectors(filtered);\n };\n\n if (!sieBase) {\n // No Experience base — do not invent Google/GitHub buttons. Fake fallbacks\n // start OIDC `direct_sign_in` and dump users on Logto `/sign-in`.\n if (!cancelled) setConnectors([]);\n return;\n }\n\n void fetchSocialConnectors({ apiBase: sieBase, appId: config.clientId })\n .then((list) => {\n apply(list);\n })\n .catch(() => {\n if (!cancelled) setConnectors([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [config.clientId, config.experienceApiBase, config.issuer, socialEnabled, socialProviders]);\n\n const runOidc = async (directSignIn?: string) => {\n if (!configured) throw new Error(\"IdP not configured\");\n if (mode === \"redirect\") {\n await signInRedirect(config, { returnUrl, directSignIn });\n return;\n }\n const { session, returnUrl: next } = await signInPopup(config, { returnUrl, directSignIn });\n await onOidcSession?.(session, next);\n };\n\n const runSocial = async (target: string) => {\n setError(\"\");\n setLoading(target);\n try {\n await runOidc(`social:${target}`);\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setLoading(null);\n }\n };\n\n const followExperienceRedirect = (redirectTo: string) => {\n if (onExperienceRedirect) {\n onExperienceRedirect(redirectTo);\n return;\n }\n window.location.assign(redirectTo);\n };\n\n const runPassword = async (event: FormEvent) => {\n event.preventDefault();\n if (!configured) return;\n setError(\"\");\n setLoading(\"password\");\n try {\n const apiBase = config.experienceApiBase?.trim();\n if (!apiBase) {\n throw new Error(labels.experienceUnavailable);\n }\n const result = await experiencePasswordSignIn({\n apiBase,\n identifier: identifier.trim(),\n password,\n issuer: config.issuer,\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n audience: config.audience,\n scopes: config.scopes,\n returnUrl,\n });\n if (result.redirectTo) {\n // Completes the PKCE interaction from bootstrap — do NOT start a new\n // authorize (that re-opens Logto hosted /sign-in).\n followExperienceRedirect(result.redirectTo);\n return;\n }\n throw new Error(\"Experience API did not return redirectTo\");\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setLoading(null);\n }\n };\n\n const busy = loading !== null;\n const showSocial = socialEnabled && connectors.length > 0;\n const showHint = Boolean(labelsProp?.hint) || showSocial;\n\n return (\n <div className={cx(styles.panel, className)} style={panelStyle}>\n <header className={styles.brand}>\n {logoSrc ? <img src={logoSrc} alt=\"\" width={48} height={48} className={styles.logo} /> : null}\n <div>\n <p className={styles.product}>{productName}</p>\n <h2 className={styles.title}>{labels.title}</h2>\n </div>\n </header>\n <p className={styles.subtitle}>{labels.subtitle}</p>\n\n {configured ? (\n <>\n <form onSubmit={(e) => void runPassword(e)} className={styles.form}>\n <input\n type=\"text\"\n name=\"identifier\"\n autoComplete=\"username\"\n placeholder={labels.identifierPlaceholder}\n value={identifier}\n onChange={(e) => setIdentifier(e.target.value)}\n className={styles.input}\n disabled={busy}\n />\n <div className={styles.passwordField}>\n <input\n type={passwordVisible ? \"text\" : \"password\"}\n name=\"password\"\n autoComplete=\"current-password\"\n placeholder={labels.passwordPlaceholder}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n className={cx(styles.input, styles.passwordInput)}\n disabled={busy}\n />\n <button\n type=\"button\"\n className={styles.passwordToggle}\n disabled={busy}\n aria-label={passwordVisible ? labels.hidePassword : labels.showPassword}\n aria-pressed={passwordVisible}\n onClick={() => setPasswordVisible((v) => !v)}\n >\n <PasswordVisibilityIcon visible={passwordVisible} />\n </button>\n </div>\n <button type=\"submit\" className={styles.primaryBtn} disabled={busy || !identifier || !password}>\n {loading === \"password\" ? \"…\" : labels.submitPassword}\n </button>\n </form>\n {showHint ? <p className={styles.hint}>{labels.hint}</p> : null}\n\n {showSocial ? (\n <div className={styles.divider} aria-hidden>\n <span className={styles.dividerLine} />\n <span className={styles.dividerText}>{labels.socialDivider}</span>\n <span className={styles.dividerLine} />\n </div>\n ) : null}\n {showSocial ? (\n <div className={styles.socialStack}>\n {connectors.map((connector) => (\n <button\n key={connector.id}\n type=\"button\"\n className={styles.socialBtn}\n disabled={busy}\n onClick={() => void runSocial(connector.target)}\n >\n <SocialLogo connector={connector} />\n {loading === connector.target ? \"…\" : labelFor(connector, labels)}\n </button>\n ))}\n </div>\n ) : null}\n\n </>\n ) : (\n <p className={styles.error}>IdP is not configured (issuer / clientId / redirectUri).</p>\n )}\n\n {error ? <p className={styles.error}>{error}</p> : null}\n\n {showCancel ? (\n <button type=\"button\" className={styles.cancelBtn} disabled={busy} onClick={onCancel}>\n {labels.cancel}\n </button>\n ) : null}\n\n {footer ? <footer className={styles.footer}>{footer}</footer> : null}\n </div>\n );\n}\n\nfunction SocialLogo({ connector }: { connector: ExperienceSocialConnector }) {\n if (connector.logo) {\n return <img src={connector.logo} alt=\"\" width={18} height={18} className={styles.socialLogo} />;\n }\n return (\n <span className={styles.logoFallback} aria-hidden>\n {connector.name.slice(0, 1).toUpperCase()}\n </span>\n );\n}\n\nfunction PasswordVisibilityIcon({ visible }: { visible: boolean }) {\n // Filled icons (antd Eye / EyeInvisible style) — no dependency.\n if (visible) {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 1024 1024\" fill=\"currentColor\" aria-hidden>\n <path d=\"M942.2 486.2C847.4 286.5 704.1 186 512 186c-57.9 0-111.5 9.8-160.3 27.7l72.3 72.3C457 273.3 483.5 266 512 266c161.3 0 279.4 81.8 362.7 254-26.3 54.4-57.5 100.2-93.3 136.1l59.6 59.6C891.4 655.7 932.5 578.5 942.2 537.7a60.3 60.3 0 000-51.5zM336.6 278.6l-59.9-59.9C230.6 255.4 182.8 296.4 141.9 348.1 95.4 412.1 64.6 486.5 51.8 512a60.3 60.3 0 000 51.5C115.3 719.5 224.6 814.8 365.4 860.1l72.5-72.5C353.6 761.6 286.3 698.3 241.3 612.5 220.6 573.1 205 528.6 194.5 486.2c24.5-50.4 55.1-92.1 90.8-124.9l51.3-51.3zM606.6 556.6A112 112 0 01467.4 417.4L606.6 556.6zM508 624c-26.5 0-50.9-9.2-70.2-24.6l-59.9 59.9A175.3 175.3 0 00508 688c97.2 0 176-78.8 176-176 0-26.5-9.2-50.9-24.6-70.2l-59.9 59.9c15.4 19.3 24.6 43.7 24.6 70.2 0 61.9-50.1 112-112 112zM880 112L112 880l48 48 768-768z\" />\n </svg>\n );\n }\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 1024 1024\" fill=\"currentColor\" aria-hidden>\n <path d=\"M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3a60.3 60.3 0 000-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766z\" />\n <path d=\"M508 336c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z\" />\n </svg>\n );\n}\n","import { useSyncExternalStore, type CSSProperties, type ReactNode } from \"react\";\nimport { authGate } from \"./auth-gate\";\nimport { HeadlessLoginPanel, type HeadlessLoginLabels } from \"./HeadlessLoginPanel\";\nimport type { LuminaryAuthSession, LuminaryIdpConfig } from \"./types\";\n\nexport interface ReauthOverlayProps {\n config: Partial<LuminaryIdpConfig>;\n productName: string;\n logoSrc?: string;\n labels?: HeadlessLoginLabels;\n returnUrl?: string;\n /** Brand accent forwarded to HeadlessLoginPanel (default `#3a84ff`). */\n themeColor?: string;\n /** Exchange OIDC token / persist product session, then AuthGate completes. */\n onOidcSession: (session: LuminaryAuthSession, returnUrl?: string) => Promise<void> | void;\n /** Optional custom body instead of HeadlessLoginPanel */\n children?: ReactNode;\n /** Allow dismiss → cancelReauth (default true for mid-session; false for hard gate). */\n dismissible?: boolean;\n onDismiss?: () => void;\n}\n\n/**\n * Full-viewport soft gate shown while AuthGate phase is `reauth` (or `refreshing` spinner).\n * Does not iframe the IdP — uses Headless panel + OIDC popup.\n */\nexport function ReauthOverlay({\n config,\n productName,\n logoSrc,\n labels,\n returnUrl,\n themeColor,\n onOidcSession,\n children,\n dismissible = true,\n onDismiss,\n}: ReauthOverlayProps) {\n const snapshot = useSyncExternalStore(authGate.subscribe, authGate.getSnapshot, authGate.getSnapshot);\n\n if (snapshot.phase === \"idle\") return null;\n\n const resolvedReturnUrl =\n returnUrl ??\n (() => {\n if (typeof window === \"undefined\") return undefined;\n const hash = window.location.hash.replace(/^#/, \"\");\n if (!hash || hash.startsWith(\"/login\") || hash.startsWith(\"/auth/\")) return undefined;\n return hash.startsWith(\"/\") ? hash : `/${hash}`;\n })();\n\n const handleSession = async (session: LuminaryAuthSession, next?: string) => {\n await onOidcSession(session, next);\n authGate.completeReauth();\n };\n\n const handleCancel = () => {\n onDismiss?.();\n authGate.cancelReauth(\"cancelled\");\n };\n\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={productName}\n style={backdropStyle}\n onClick={dismissible ? handleCancel : undefined}\n >\n <div style={centerStyle} onClick={(e) => e.stopPropagation()}>\n {snapshot.phase === \"refreshing\" ? (\n <div style={spinnerCardStyle}>\n <div style={spinnerStyle} />\n <p style={{ margin: 0, color: \"#e8eef2\" }}>Refreshing session…</p>\n </div>\n ) : children ? (\n children\n ) : (\n <HeadlessLoginPanel\n config={config}\n productName={productName}\n logoSrc={logoSrc}\n themeColor={themeColor}\n labels={{\n title: labels?.title ?? \"Session expired\",\n subtitle: labels?.subtitle ?? \"Sign in again to keep working — this page will not reload.\",\n ...labels,\n }}\n returnUrl={resolvedReturnUrl}\n mode=\"popup\"\n showCancel={dismissible}\n onCancel={handleCancel}\n onOidcSession={handleSession}\n />\n )}\n </div>\n </div>\n );\n}\n\nconst backdropStyle: CSSProperties = {\n position: \"fixed\",\n inset: 0,\n zIndex: 10000,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 24,\n background:\n \"radial-gradient(1200px 600px at 20% 10%, rgba(56, 120, 150, 0.35), transparent 55%), rgba(10, 18, 24, 0.72)\",\n backdropFilter: \"blur(6px)\",\n};\n\nconst centerStyle: CSSProperties = {\n width: \"min(100%, 420px)\",\n};\n\nconst spinnerCardStyle: CSSProperties = {\n display: \"grid\",\n justifyItems: \"center\",\n gap: 14,\n padding: 28,\n borderRadius: 16,\n background: \"rgba(20, 32, 40, 0.88)\",\n};\n\nconst spinnerStyle: CSSProperties = {\n width: 36,\n height: 36,\n borderRadius: \"50%\",\n border: \"3px solid rgba(255,255,255,0.2)\",\n borderTopColor: \"#7ec8e3\",\n animation: \"luminary-auth-spin 0.8s linear infinite\",\n};\n\n// Inject keyframes once\nif (typeof document !== \"undefined\" && !document.getElementById(\"luminary-auth-spin-style\")) {\n const style = document.createElement(\"style\");\n style.id = \"luminary-auth-spin-style\";\n style.textContent = `@keyframes luminary-auth-spin { to { transform: rotate(360deg); } }`;\n document.head.appendChild(style);\n}\n","import { createContext, useContext, useEffect, useMemo, type ReactNode } from \"react\";\nimport { useSyncExternalStore } from \"react\";\nimport { authGate, type AuthGateConfig, type AuthGateSnapshot } from \"./auth-gate\";\nimport { ReauthOverlay, type ReauthOverlayProps } from \"./ReauthOverlay\";\nimport type { LuminaryAuthSession, LuminaryIdpConfig } from \"./types\";\n\ninterface AuthGateContextValue {\n snapshot: AuthGateSnapshot;\n requestReauth: (message?: string) => Promise<\"retry\" | \"fail\">;\n completeReauth: () => void;\n cancelReauth: (message?: string) => void;\n}\n\nconst AuthGateContext = createContext<AuthGateContextValue | null>(null);\n\nexport interface AuthGateProviderProps extends AuthGateConfig {\n children: ReactNode;\n /** When set, mounts {@link ReauthOverlay} automatically. */\n overlay?: Omit<ReauthOverlayProps, \"onOidcSession\"> & {\n onOidcSession: (session: LuminaryAuthSession, returnUrl?: string) => Promise<void> | void;\n config: Partial<LuminaryIdpConfig>;\n };\n}\n\nexport function AuthGateProvider({\n children,\n tryRefresh,\n onReauthRequired,\n onSettled,\n overlay,\n}: AuthGateProviderProps) {\n useEffect(() => {\n authGate.configure({ tryRefresh, onReauthRequired, onSettled });\n }, [tryRefresh, onReauthRequired, onSettled]);\n\n const snapshot = useSyncExternalStore(authGate.subscribe, authGate.getSnapshot, authGate.getSnapshot);\n\n const value = useMemo<AuthGateContextValue>(\n () => ({\n snapshot,\n requestReauth: (message?: string) => authGate.requestReauth(message),\n completeReauth: () => authGate.completeReauth(),\n cancelReauth: (message?: string) => authGate.cancelReauth(message),\n }),\n [snapshot],\n );\n\n return (\n <AuthGateContext.Provider value={value}>\n {children}\n {overlay ? <ReauthOverlay {...overlay} /> : null}\n </AuthGateContext.Provider>\n );\n}\n\nexport function useAuthGate(): AuthGateContextValue {\n const ctx = useContext(AuthGateContext);\n if (!ctx) throw new Error(\"useAuthGate must be used within AuthGateProvider\");\n return ctx;\n}\n\n/** Optional hook — returns null outside provider (for shared API helpers). */\nexport function useAuthGateOptional(): AuthGateContextValue | null {\n return useContext(AuthGateContext);\n}\n","export interface PostLoginPathOptions {\n /** sessionStorage key (product-scoped), e.g. `dv:postLoginPath` */\n storageKey: string;\n /** Default destination when nothing remembered */\n defaultPath?: string;\n /** Extra paths that must not be used as return targets */\n unsafePrefixes?: string[];\n}\n\nconst DEFAULT_UNSAFE = [\"/login\", \"/auth\", \"/exception\"];\n\nfunction normalizeAppPath(path: string, fallback: string): string {\n const raw = path.replace(/^#/, \"\").trim();\n if (!raw) return fallback.startsWith(\"/\") ? fallback : `/${fallback}`;\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nfunction isUnsafeReturnPath(path: string, unsafePrefixes: string[], fallback: string): boolean {\n const p = normalizeAppPath(path, fallback);\n if (p === \"/\") return true;\n return unsafePrefixes.some((prefix) => p === prefix || p.startsWith(`${prefix}/`) || p.startsWith(prefix));\n}\n\n/**\n * sessionStorage helpers for OIDC redirect return paths.\n * Product-specific ACL checks (e.g. 403 fallback) stay in the product.\n */\nexport function createPostLoginPathHelpers(options: PostLoginPathOptions) {\n const storageKey = options.storageKey;\n const defaultPath = options.defaultPath?.startsWith(\"/\")\n ? options.defaultPath\n : `/${options.defaultPath || \"home\"}`;\n const unsafePrefixes = [...DEFAULT_UNSAFE, ...(options.unsafePrefixes || [])];\n\n function rememberPostLoginPath(path: string): void {\n const normalized = normalizeAppPath(path, defaultPath);\n if (isUnsafeReturnPath(normalized, unsafePrefixes, defaultPath)) return;\n try {\n sessionStorage.setItem(storageKey, normalized);\n } catch {\n /* ignore */\n }\n }\n\n function peekPostLoginPath(): string | undefined {\n try {\n const v = sessionStorage.getItem(storageKey);\n if (!v || isUnsafeReturnPath(v, unsafePrefixes, defaultPath)) return undefined;\n return normalizeAppPath(v, defaultPath);\n } catch {\n return undefined;\n }\n }\n\n function consumePostLoginPath(fallback = defaultPath): string {\n const remembered = peekPostLoginPath();\n try {\n sessionStorage.removeItem(storageKey);\n } catch {\n /* ignore */\n }\n return remembered ?? normalizeAppPath(fallback, defaultPath);\n }\n\n return {\n rememberPostLoginPath,\n peekPostLoginPath,\n consumePostLoginPath,\n normalizeAppPath: (path: string) => normalizeAppPath(path, defaultPath),\n isUnsafeReturnPath: (path: string) => isUnsafeReturnPath(path, unsafePrefixes, defaultPath),\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/types.ts","../src/login-experience-adapter.ts","../src/logto-experience-adapter.ts","../src/oidc-client.ts","../src/experience-client.ts","../src/auth-gate.ts","../src/LuminaryAuthProvider.tsx","../src/HeadlessLoginPanel.module.scss","../src/HeadlessLoginPanel.tsx","../src/ReauthOverlay.tsx","../src/AuthGateProvider.tsx","../src/post-login-path.ts"],"names":["WebStorageStateStore","UserManager","OidcClient","createContext","useMemo","useState","useCallback","useEffect","jsx","useContext","panel","brand","logo","product","title","subtitle","form","socialStack","input","passwordField","passwordInput","passwordToggle","primaryBtn","socialBtn","socialLogo","logoFallback","cancelBtn","divider","dividerLine","dividerText","hint","error","footer","jsxs","Fragment","useSyncExternalStore","storageKey"],"mappings":"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","file":"index.js","sourcesContent":["export interface LuminaryIdpConfig {\n /**\n * OIDC issuer. Prefer Auth Gateway (`http://localhost:3010/oidc`) so products\n * stay IdP-agnostic; direct Logto issuer is OK for local MVP.\n */\n issuer: string;\n clientId: string;\n redirectUri: string;\n /**\n * Popup OIDC callback. Defaults to `redirectUri` (same `/auth/callback`).\n * Must be registered on the IdP application.\n */\n popupRedirectUri?: string;\n postLogoutRedirectUri?: string;\n scopes?: string;\n /** API resource indicator (access token `aud`) */\n audience?: string;\n /** localStorage key for access token */\n tokenStorageKey?: string;\n /**\n * Logto Experience API base (no trailing slash), e.g. Auth Gateway\n * `http://localhost:3010` or direct Logto `http://localhost:3001`.\n * When set, Headless password sign-in is attempted before OIDC popup fallback.\n */\n experienceApiBase?: string;\n}\n\nexport interface LuminaryAuthSession {\n accessToken: string;\n idToken?: string;\n expiresAt?: number;\n profile?: Record<string, unknown>;\n}\n\nexport function isIdpConfigured(config: Partial<LuminaryIdpConfig>): config is LuminaryIdpConfig {\n return Boolean(config.issuer && config.clientId && config.redirectUri);\n}\n\n/** Resolve issuer from Auth Gateway base URL or direct IDP_ISSUER. */\nexport function resolveIssuer(env: Record<string, string | undefined>): string | undefined {\n // Prefer explicit IdP issuer so JWT `iss` validation matches Logto.\n // Auth Gateway is a CORS/proxy front — set via VITE_AUTH_EXPERIENCE_URL / VITE_AUTH_GATEWAY_URL.\n const explicit = env.VITE_IDP_ISSUER ?? env.PUBLIC_IDP_ISSUER ?? env.IDP_ISSUER;\n if (explicit) return explicit;\n const gateway = env.VITE_AUTH_GATEWAY_URL ?? env.PUBLIC_AUTH_GATEWAY_URL ?? env.AUTH_GATEWAY_URL;\n if (gateway) return `${gateway.replace(/\\/$/, \"\")}/oidc`;\n return undefined;\n}\n\n/** Derive Experience API host from Gateway URL or by stripping `/oidc` from issuer. */\nexport function resolveExperienceApiBase(env: Record<string, string | undefined>): string | undefined {\n const explicit =\n env.VITE_AUTH_EXPERIENCE_URL ??\n env.PUBLIC_AUTH_EXPERIENCE_URL ??\n env.AUTH_EXPERIENCE_URL;\n if (explicit) return explicit.replace(/\\/$/, \"\");\n\n const gateway = env.VITE_AUTH_GATEWAY_URL ?? env.PUBLIC_AUTH_GATEWAY_URL ?? env.AUTH_GATEWAY_URL;\n if (gateway) return gateway.replace(/\\/$/, \"\");\n\n const issuer = resolveIssuer(env);\n if (!issuer) return undefined;\n return issuer.replace(/\\/$/, \"\").replace(/\\/oidc$/i, \"\");\n}\n\nexport function readIdpConfigFromEnv(env: Record<string, string | undefined>): Partial<LuminaryIdpConfig> {\n const redirectUri = env.VITE_IDP_REDIRECT_URI ?? env.PUBLIC_IDP_REDIRECT_URI ?? \"\";\n return {\n issuer: resolveIssuer(env),\n clientId: env.VITE_IDP_CLIENT_ID ?? env.PUBLIC_IDP_CLIENT_ID,\n redirectUri,\n popupRedirectUri: env.VITE_IDP_POPUP_REDIRECT_URI ?? env.PUBLIC_IDP_POPUP_REDIRECT_URI ?? redirectUri,\n postLogoutRedirectUri: env.VITE_IDP_POST_LOGOUT_URI ?? env.PUBLIC_IDP_POST_LOGOUT_URI,\n scopes: env.VITE_IDP_SCOPES ?? env.PUBLIC_IDP_SCOPES ?? \"openid profile email offline_access\",\n audience: env.VITE_IDP_AUDIENCE ?? env.PUBLIC_IDP_AUDIENCE,\n tokenStorageKey: env.VITE_IDP_TOKEN_KEY ?? \"luminary_access_token\",\n experienceApiBase: resolveExperienceApiBase(env),\n };\n}\n","import { LogtoExperienceAdapter } from \"./logto-experience-adapter\";\n\n/**\n * Capabilities exposed by a headless login-experience provider.\n *\n * Consumers can use these flags to avoid assuming that every provider supports\n * Logto's password, connector-discovery, or direct social-login flows.\n */\nexport const LOGIN_EXPERIENCE_CAPABILITIES = {\n passwordSignIn: \"password-sign-in\",\n socialConnectors: \"social-connectors\",\n socialDirectSignIn: \"social-direct-sign-in\",\n} as const;\n\nexport type LoginExperienceCapability =\n (typeof LOGIN_EXPERIENCE_CAPABILITIES)[keyof typeof LOGIN_EXPERIENCE_CAPABILITIES];\n\nexport type ExperienceIdentifierType = \"email\" | \"username\" | \"phone\";\n\nexport interface ExperiencePasswordSignInInput {\n /** Experience API origin (no trailing slash). Prefer SPA origin when proxied. */\n apiBase: string;\n identifier: string;\n password: string;\n identifierType?: ExperienceIdentifierType;\n /** Required to bootstrap the OIDC interaction cookie before Experience calls. */\n issuer?: string;\n clientId?: string;\n redirectUri?: string;\n audience?: string;\n scopes?: string;\n /** Carried in OIDC state for post-login return (UserManager PKCE). */\n returnUrl?: string;\n}\n\nexport interface ExperiencePasswordSignInResult {\n /** Continue URL from Experience submit (complete OIDC interaction). */\n redirectTo?: string;\n raw?: unknown;\n}\n\nexport interface ExperienceSocialConnector {\n id: string;\n target: string;\n name: string;\n logo?: string;\n}\n\nexport interface FetchSocialConnectorsInput {\n /** Same origin as Experience / IdP (e.g. SPA proxy or http://localhost:3001). */\n apiBase: string;\n appId?: string;\n}\n\nexport interface SocialSignInRequest {\n /** Provider-specific authorize parameters, passed through by the OIDC client. */\n extraQueryParams?: Record<string, string>;\n}\n\n/**\n * Provider boundary for non-standard login-experience APIs.\n *\n * Standard OIDC redirect/popup and PKCE handling intentionally remain in the\n * OIDC client. Only provider-specific Experience operations belong here.\n */\nexport interface LoginExperienceAdapter {\n readonly provider: string;\n readonly capabilities: readonly LoginExperienceCapability[];\n experiencePasswordSignIn?(\n input: ExperiencePasswordSignInInput,\n ): Promise<ExperiencePasswordSignInResult>;\n fetchSocialConnectors?(\n input: FetchSocialConnectorsInput,\n ): Promise<ExperienceSocialConnector[]>;\n createSocialSignInRequest?(target: string): SocialSignInRequest;\n}\n\nexport type LoginExperienceProvider = \"logto\";\n\n/**\n * Factory for built-in providers. Logto is intentionally the only built-in\n * adapter; products can supply their own adapter without shipping fake stubs.\n */\nexport function createLoginExperienceAdapter(\n provider: LoginExperienceProvider = \"logto\",\n): LoginExperienceAdapter {\n switch (provider) {\n case \"logto\":\n return new LogtoExperienceAdapter();\n }\n}\n\nlet defaultAdapter: LoginExperienceAdapter | undefined;\n\n/** Resolve an explicit product adapter, or the backward-compatible Logto default. */\nexport function resolveLoginExperienceAdapter(\n adapter?: LoginExperienceAdapter | null,\n): LoginExperienceAdapter {\n if (adapter) return adapter;\n defaultAdapter ??= createLoginExperienceAdapter();\n return defaultAdapter;\n}\n","/**\n * Logto Experience API (Headless) adapter.\n * Prefer same-origin Experience base (SPA proxies /api/experience) so cookies\n * work on HTTP localhost.\n */\n\nimport { prepareSignInRequestUrl } from \"./oidc-client\";\nimport {\n LOGIN_EXPERIENCE_CAPABILITIES,\n type ExperienceIdentifierType,\n type ExperiencePasswordSignInInput,\n type ExperiencePasswordSignInResult,\n type ExperienceSocialConnector,\n type FetchSocialConnectorsInput,\n type LoginExperienceAdapter,\n type LoginExperienceCapability,\n type SocialSignInRequest,\n} from \"./login-experience-adapter\";\nimport type { LuminaryIdpConfig } from \"./types\";\n\nfunction experienceUrl(apiBase: string, path: string): string {\n return `${apiBase.replace(/\\/$/, \"\")}/api/experience${path}`;\n}\n\nasync function experienceFetch<T>(apiBase: string, path: string, init: RequestInit): Promise<T> {\n const res = await fetch(experienceUrl(apiBase, path), {\n credentials: \"include\",\n ...init,\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...(init.headers ?? {}),\n },\n });\n const text = await res.text();\n let data: unknown = null;\n if (text) {\n try {\n data = JSON.parse(text) as unknown;\n } catch {\n data = text;\n }\n }\n if (!res.ok) {\n const msg =\n data && typeof data === \"object\" && data !== null && \"message\" in data\n ? String((data as { message: unknown }).message)\n : `Experience API ${res.status}`;\n throw new Error(msg);\n }\n return data as T;\n}\n\nfunction guessIdentifierType(identifier: string): ExperienceIdentifierType {\n if (identifier.includes(\"@\")) return \"email\";\n if (/^\\+?\\d{6,}$/.test(identifier.trim())) return \"phone\";\n return \"username\";\n}\n\n/**\n * Force authorize onto the Experience/SPA origin so Set-Cookie lands on the\n * same host as subsequent `/api/experience` calls (dev proxy strips Domain).\n */\nexport function sameOriginAuthorizeUrl(authorizeUrl: string, apiBase: string): string {\n const u = new URL(authorizeUrl);\n const base = new URL(apiBase);\n if (u.origin === base.origin) return authorizeUrl;\n return `${base.origin}${u.pathname}${u.search}${u.hash}`;\n}\n\n/**\n * Logto creates its interaction cookie after an authorize request. The\n * standard OIDC client creates and persists the PKCE request; this adapter only\n * applies Logto's same-origin interaction bootstrap.\n */\nasync function bootstrapOidcInteraction(input: ExperiencePasswordSignInInput): Promise<void> {\n if (!input.issuer || !input.clientId || !input.redirectUri) return;\n if (typeof document === \"undefined\") return;\n\n const config: LuminaryIdpConfig = {\n issuer: input.issuer,\n clientId: input.clientId,\n redirectUri: input.redirectUri,\n audience: input.audience,\n scopes: input.scopes,\n experienceApiBase: input.apiBase,\n };\n\n const signinUrl = await prepareSignInRequestUrl(config, {\n returnUrl: input.returnUrl,\n });\n const authorizeUrl = sameOriginAuthorizeUrl(signinUrl, input.apiBase);\n\n await new Promise<void>((resolve) => {\n const iframe = document.createElement(\"iframe\");\n iframe.setAttribute(\"aria-hidden\", \"true\");\n iframe.tabIndex = -1;\n iframe.style.cssText = \"position:absolute;width:0;height:0;border:0;visibility:hidden\";\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n iframe.remove();\n resolve();\n };\n iframe.addEventListener(\"load\", () => {\n window.setTimeout(finish, 400);\n });\n iframe.src = authorizeUrl;\n document.body.appendChild(iframe);\n window.setTimeout(finish, 2500);\n });\n}\n\n/** Build Logto's provider-specific direct sign-in authorize parameter. */\nexport function createLogtoDirectSignInRequest(directSignIn: string): SocialSignInRequest {\n return { extraQueryParams: { direct_sign_in: directSignIn } };\n}\n\n/** Built-in adapter for Logto's non-standard Experience API. */\nexport class LogtoExperienceAdapter implements LoginExperienceAdapter {\n readonly provider = \"logto\";\n readonly capabilities: readonly LoginExperienceCapability[] = [\n LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn,\n LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors,\n LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn,\n ];\n\n async experiencePasswordSignIn(\n input: ExperiencePasswordSignInInput,\n ): Promise<ExperiencePasswordSignInResult> {\n const { apiBase, identifier, password } = input;\n await bootstrapOidcInteraction(input);\n\n const primary = input.identifierType ?? guessIdentifierType(identifier);\n const alternates: ExperienceIdentifierType[] =\n primary === \"phone\"\n ? [primary]\n : primary === \"email\"\n ? [\"email\", \"username\"]\n : [\"username\", \"email\"];\n\n let lastError: Error | undefined;\n for (const identifierType of alternates) {\n try {\n await experienceFetch(apiBase, \"\", {\n method: \"PUT\",\n body: JSON.stringify({ interactionEvent: \"SignIn\" }),\n });\n\n const verified = await experienceFetch<{ verificationId?: string }>(\n apiBase,\n \"/verification/password\",\n {\n method: \"POST\",\n body: JSON.stringify({\n identifier: { type: identifierType, value: identifier },\n password,\n }),\n },\n );\n\n const verificationId = verified?.verificationId;\n if (!verificationId) {\n throw new Error(\"Experience API did not return verificationId\");\n }\n\n await experienceFetch(apiBase, \"/identification\", {\n method: \"POST\",\n body: JSON.stringify({ verificationId }),\n });\n\n const submitted = await experienceFetch<{ redirectTo?: string }>(\n apiBase,\n \"/submit\",\n {\n method: \"POST\",\n body: JSON.stringify({}),\n },\n );\n\n return { redirectTo: submitted?.redirectTo, raw: submitted };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n }\n }\n throw lastError ?? new Error(\"Experience password sign-in failed\");\n }\n\n async fetchSocialConnectors(\n input: FetchSocialConnectorsInput,\n ): Promise<ExperienceSocialConnector[]> {\n const url = new URL(`${input.apiBase.replace(/\\/$/, \"\")}/api/.well-known/sign-in-exp`);\n if (input.appId?.trim()) url.searchParams.set(\"appId\", input.appId.trim());\n const res = await fetch(url.toString(), {\n // Public metadata — omit cookies so browsers do not require credentialed CORS.\n credentials: \"omit\",\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) {\n throw new Error(`sign-in-exp ${res.status}`);\n }\n const data = (await res.json()) as {\n socialConnectors?: Array<{\n id?: string;\n target?: string;\n name?: string | Record<string, string>;\n logo?: string;\n }>;\n };\n return (data.socialConnectors ?? [])\n .filter(\n (\n connector,\n ): connector is {\n id: string;\n target: string;\n name?: string | Record<string, string>;\n logo?: string;\n } => Boolean(connector?.id && connector?.target),\n )\n .map((connector) => ({\n id: connector.id,\n target: connector.target,\n name: localizeName(connector.name) || titleCase(connector.target),\n logo: connector.logo,\n }));\n }\n\n createSocialSignInRequest(target: string): SocialSignInRequest {\n return createLogtoDirectSignInRequest(`social:${target}`);\n }\n}\n\nfunction localizeName(name: string | Record<string, string> | undefined): string {\n if (!name) return \"\";\n if (typeof name === \"string\") return name;\n return name[\"zh-CN\"] || name.en || Object.values(name)[0] || \"\";\n}\n\nfunction titleCase(target: string): string {\n if (!target) return \"\";\n return target.charAt(0).toUpperCase() + target.slice(1);\n}\n","import {\n OidcClient,\n UserManager,\n WebStorageStateStore,\n type User,\n} from \"oidc-client-ts\";\nimport { createLogtoDirectSignInRequest } from \"./logto-experience-adapter\";\nimport type { LuminaryAuthSession, LuminaryIdpConfig } from \"./types\";\n\nlet manager: UserManager | null = null;\n\nfunction storageKey(config: LuminaryIdpConfig): string {\n return config.tokenStorageKey ?? \"luminary_access_token\";\n}\n\nfunction popupRedirectUri(config: LuminaryIdpConfig): string {\n return config.popupRedirectUri ?? config.redirectUri;\n}\n\nfunction sharedStateStore() {\n // localStorage so popup/redirect/Experience callback windows can resolve PKCE state.\n return new WebStorageStateStore({ store: window.localStorage });\n}\n\nfunction clientSettings(config: LuminaryIdpConfig) {\n const resource = config.audience?.trim() || undefined;\n return {\n authority: config.issuer.replace(/\\/$/, \"\"),\n metadataUrl: resolveOidcMetadataUrl(config),\n client_id: config.clientId,\n redirect_uri: config.redirectUri,\n post_logout_redirect_uri: config.postLogoutRedirectUri ?? config.redirectUri,\n response_type: \"code\" as const,\n scope: config.scopes ?? \"openid profile email offline_access\",\n stateStore: sharedStateStore(),\n extraQueryParams: resource ? { resource } : undefined,\n extraTokenParams: resource ? { resource } : undefined,\n };\n}\n\nfunction userManagerSettings(config: LuminaryIdpConfig) {\n const resource = config.audience?.trim() || undefined;\n return {\n ...clientSettings(config),\n popup_redirect_uri: popupRedirectUri(config),\n automaticSilentRenew: true,\n loadUserInfo: !resource,\n userStore: sharedStateStore(),\n };\n}\n\nexport function createUserManager(config: LuminaryIdpConfig): UserManager {\n if (manager) return manager;\n manager = new UserManager(userManagerSettings(config));\n return manager;\n}\n\n/**\n * When Experience/Gateway base differs from the IdP issuer origin, fetch OIDC discovery\n * via the gateway (CORS) while keeping `authority` = Logto issuer (JWT `iss`).\n */\nfunction resolveOidcMetadataUrl(config: LuminaryIdpConfig): string | undefined {\n const proxyBase = config.experienceApiBase?.replace(/\\/$/, \"\");\n if (!proxyBase) return undefined;\n try {\n if (new URL(proxyBase).origin === new URL(config.issuer).origin) return undefined;\n } catch {\n return undefined;\n }\n return `${proxyBase}/oidc/.well-known/openid-configuration`;\n}\n\nexport function resetUserManager(): void {\n manager = null;\n}\n\nexport interface SignInOptions {\n returnUrl?: string;\n /** Provider-specific authorize parameters supplied by an experience adapter. */\n extraQueryParams?: Record<string, string>;\n /**\n * Logto direct sign-in, e.g. `social:google` / `social:github` / `sso:<connectorId>`.\n * Skips the hosted password page and opens the provider immediately.\n * @deprecated Prefer a LoginExperienceAdapter, which supplies extraQueryParams.\n */\n directSignIn?: string;\n}\n\nfunction signInArgs(config: LuminaryIdpConfig, options?: SignInOptions | string) {\n const normalized: SignInOptions =\n typeof options === \"string\" ? { returnUrl: options } : (options ?? {});\n const resource = config.audience?.trim();\n const extraQueryParams: Record<string, string> = { ...normalized.extraQueryParams };\n if (resource) extraQueryParams.resource = resource;\n if (normalized.directSignIn) {\n Object.assign(\n extraQueryParams,\n createLogtoDirectSignInRequest(normalized.directSignIn).extraQueryParams,\n );\n }\n return {\n state: normalized.returnUrl ? { returnUrl: normalized.returnUrl } : undefined,\n extraQueryParams: Object.keys(extraQueryParams).length ? extraQueryParams : undefined,\n };\n}\n\nexport async function signInRedirect(\n config: LuminaryIdpConfig,\n returnUrlOrOptions?: string | SignInOptions,\n): Promise<void> {\n resetUserManager();\n const um = createUserManager(config);\n await um.signinRedirect(signInArgs(config, returnUrlOrOptions));\n}\n\n/**\n * Persist PKCE state (same store as {@link createUserManager}) and return the\n * authorize URL — used by Experience headless bootstrap before navigating to\n * `redirectTo` from `/api/experience/submit`.\n */\nexport async function prepareSignInRequestUrl(\n config: LuminaryIdpConfig,\n returnUrlOrOptions?: string | SignInOptions,\n): Promise<string> {\n resetUserManager();\n // Warm the singleton so callback uses identical settings/stores.\n createUserManager(config);\n const client = new OidcClient(clientSettings(config));\n const args = signInArgs(config, returnUrlOrOptions);\n const request = await client.createSigninRequest({\n state: args.state,\n extraQueryParams: {\n ...(args.extraQueryParams ?? {}),\n prompt: \"login\",\n },\n });\n return request.url;\n}\n\n/**\n * OIDC login in a popup window (not an iframe). Opener keeps SPA state;\n * callback page in the popup must call {@link handleSignInPopupCallback}.\n */\nexport async function signInPopup(\n config: LuminaryIdpConfig,\n returnUrlOrOptions?: string | SignInOptions,\n): Promise<{ session: LuminaryAuthSession; returnUrl?: string }> {\n resetUserManager();\n const um = createUserManager(config);\n const user = await um.signinPopup(signInArgs(config, returnUrlOrOptions));\n const session = toSession(user);\n if (!session.accessToken) {\n throw new Error(\"IdP did not return access_token (check audience / API resource)\");\n }\n assertJwtAccessToken(session.accessToken);\n localStorage.setItem(storageKey(config), session.accessToken);\n const stateReturnUrl =\n typeof user.state === \"object\" && user.state && \"returnUrl\" in user.state\n ? String((user.state as { returnUrl?: string }).returnUrl ?? \"\")\n : undefined;\n return { session, returnUrl: stateReturnUrl || undefined };\n}\n\nexport async function handleSignInCallback(config: LuminaryIdpConfig): Promise<{\n session: LuminaryAuthSession;\n returnUrl?: string;\n}> {\n const um = createUserManager(config);\n const user = await um.signinRedirectCallback();\n const session = toSession(user);\n assertJwtAccessToken(session.accessToken);\n localStorage.setItem(storageKey(config), session.accessToken);\n const returnUrl =\n typeof user.state === \"object\" && user.state && \"returnUrl\" in user.state\n ? String((user.state as { returnUrl?: string }).returnUrl ?? \"\")\n : undefined;\n return { session, returnUrl: returnUrl || undefined };\n}\n\n/**\n * Complete popup OIDC in the popup window. Notifies the opener and closes.\n * Do not run product SSO exchange here — the opener handles that after signInPopup resolves.\n */\nexport async function handleSignInPopupCallback(config: LuminaryIdpConfig): Promise<void> {\n const um = createUserManager(config);\n await um.signinPopupCallback();\n}\n\n/** True when this window is likely an OIDC popup callback. */\nexport function isOidcPopupWindow(): boolean {\n try {\n return Boolean(window.opener && window.opener !== window);\n } catch {\n return false;\n }\n}\n\nexport async function signOutRedirect(config: LuminaryIdpConfig): Promise<void> {\n localStorage.removeItem(storageKey(config));\n const um = createUserManager(config);\n await um.signoutRedirect();\n}\n\nexport function getStoredAccessToken(config: LuminaryIdpConfig): string | null {\n return localStorage.getItem(storageKey(config));\n}\n\nexport function clearStoredSession(config: LuminaryIdpConfig): void {\n localStorage.removeItem(storageKey(config));\n}\n\nfunction toSession(user: User): LuminaryAuthSession {\n return {\n accessToken: user.access_token,\n idToken: user.id_token,\n expiresAt: user.expires_at ? user.expires_at * 1000 : undefined,\n profile: user.profile as Record<string, unknown>,\n };\n}\n\nfunction assertJwtAccessToken(accessToken: string): void {\n if (accessToken.split(\".\").length !== 3) {\n throw new Error(\n \"Received non-JWT access_token. Pass resource (audience) on authorize/token and register the API resource at the IdP.\",\n );\n }\n}\n\nexport async function getCurrentUser(config: LuminaryIdpConfig): Promise<LuminaryAuthSession | null> {\n const um = createUserManager(config);\n const user = await um.getUser();\n if (!user || user.expired) return null;\n return toSession(user);\n}\n","/**\n * @deprecated Import the adapter APIs from the package root instead.\n *\n * This module remains as a compatibility facade for existing consumers.\n */\nimport {\n LOGIN_EXPERIENCE_CAPABILITIES,\n resolveLoginExperienceAdapter,\n} from \"./login-experience-adapter\";\n\nexport type {\n ExperienceIdentifierType,\n ExperiencePasswordSignInInput,\n ExperiencePasswordSignInResult,\n ExperienceSocialConnector,\n FetchSocialConnectorsInput,\n} from \"./login-experience-adapter\";\nexport { sameOriginAuthorizeUrl } from \"./logto-experience-adapter\";\n\nimport type {\n ExperiencePasswordSignInInput,\n ExperiencePasswordSignInResult,\n ExperienceSocialConnector,\n FetchSocialConnectorsInput,\n} from \"./login-experience-adapter\";\n\n/** @deprecated Use a LoginExperienceAdapter instance. */\nexport function experiencePasswordSignIn(\n input: ExperiencePasswordSignInInput,\n): Promise<ExperiencePasswordSignInResult> {\n const adapter = resolveLoginExperienceAdapter();\n if (\n !adapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn) ||\n !adapter.experiencePasswordSignIn\n ) {\n return Promise.reject(new Error(\"Login experience does not support password sign-in\"));\n }\n return adapter.experiencePasswordSignIn(input);\n}\n\n/** @deprecated Use a LoginExperienceAdapter instance. */\nexport function fetchSocialConnectors(\n input: FetchSocialConnectorsInput,\n): Promise<ExperienceSocialConnector[]> {\n const adapter = resolveLoginExperienceAdapter();\n if (\n !adapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors) ||\n !adapter.fetchSocialConnectors\n ) {\n return Promise.reject(new Error(\"Login experience does not support social connectors\"));\n }\n return adapter.fetchSocialConnectors(input);\n}\n","/**\n * AuthGate — single-flight 401 recovery with optional token refresh + reauth UI.\n * Products wire tryRefresh / onReauthRequired; API clients call handleUnauthorized + waitIfBlocked.\n */\n\nexport type AuthGatePhase = \"idle\" | \"refreshing\" | \"reauth\";\n\nexport type UnauthorizedDisposition = \"retry\" | \"fail\";\n\nexport interface AuthGateSnapshot {\n phase: AuthGatePhase;\n /** True while refresh or interactive reauth is in flight. */\n blocked: boolean;\n lastError?: string;\n}\n\nexport interface AuthGateConfig {\n /**\n * Attempt silent product-token (or OIDC) refresh before showing reauth UI.\n * Return true if a new session was established.\n */\n tryRefresh?: () => Promise<boolean>;\n /** Called once when interactive reauth is required (open modal / popup). */\n onReauthRequired?: () => void;\n /** Called when reauth succeeds or is cancelled (phase back to idle). */\n onSettled?: (ok: boolean) => void;\n}\n\ntype Waiter = {\n resolve: (disposition: UnauthorizedDisposition) => void;\n};\n\nclass AuthGateCoordinator {\n private phase: AuthGatePhase = \"idle\";\n private lastError?: string;\n /** Cached for useSyncExternalStore — must keep referential equality when unchanged. */\n private snapshot: AuthGateSnapshot = { phase: \"idle\", blocked: false };\n private config: AuthGateConfig = {};\n private flight: Promise<UnauthorizedDisposition> | null = null;\n private reauthWaiters: Waiter[] = [];\n private listeners = new Set<() => void>();\n\n configure(config: AuthGateConfig): void {\n this.config = { ...this.config, ...config };\n }\n\n getSnapshot = (): AuthGateSnapshot => this.snapshot;\n\n subscribe = (listener: () => void): (() => void) => {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n };\n\n private emit(): void {\n for (const listener of this.listeners) listener();\n }\n\n private setPhase(phase: AuthGatePhase, lastError?: string): void {\n if (this.phase === phase && this.lastError === lastError) return;\n this.phase = phase;\n this.lastError = lastError;\n this.snapshot = {\n phase,\n blocked: phase !== \"idle\",\n lastError,\n };\n this.emit();\n }\n\n /** Await while a recovery is in flight (pause outbound API traffic). */\n async waitIfBlocked(): Promise<void> {\n if (!this.flight) return;\n await this.flight;\n }\n\n /**\n * Single-flight 401 handler.\n * Concurrent callers share one recovery; all receive the same disposition.\n */\n handleUnauthorized(errorMessage?: string): Promise<UnauthorizedDisposition> {\n if (this.flight) return this.flight;\n this.flight = this.runRecovery(errorMessage).finally(() => {\n this.flight = null;\n });\n return this.flight;\n }\n\n /** Open reauth UI without a preceding 401 (cold start / deep link). */\n requestReauth(errorMessage?: string): Promise<UnauthorizedDisposition> {\n return this.handleUnauthorized(errorMessage);\n }\n\n /** Product calls after popup / Headless login restored the session. */\n completeReauth(): void {\n if (this.phase !== \"reauth\") return;\n const waiters = this.reauthWaiters.splice(0, this.reauthWaiters.length);\n this.setPhase(\"idle\");\n this.config.onSettled?.(true);\n for (const w of waiters) w.resolve(\"retry\");\n }\n\n /** User dismissed reauth; fail queued recovery waiters. */\n cancelReauth(errorMessage?: string): void {\n if (this.phase !== \"reauth\") return;\n const waiters = this.reauthWaiters.splice(0, this.reauthWaiters.length);\n this.setPhase(\"idle\", errorMessage);\n this.config.onSettled?.(false);\n for (const w of waiters) w.resolve(\"fail\");\n }\n\n private async runRecovery(errorMessage?: string): Promise<UnauthorizedDisposition> {\n this.lastError = errorMessage;\n\n if (this.config.tryRefresh) {\n this.setPhase(\"refreshing\", errorMessage);\n try {\n const ok = await this.config.tryRefresh();\n if (ok) {\n this.setPhase(\"idle\");\n this.config.onSettled?.(true);\n return \"retry\";\n }\n } catch (e) {\n this.lastError = e instanceof Error ? e.message : String(e);\n }\n }\n\n this.setPhase(\"reauth\", this.lastError);\n this.config.onReauthRequired?.();\n\n return new Promise<UnauthorizedDisposition>((resolve) => {\n this.reauthWaiters.push({ resolve });\n });\n }\n}\n\n/** Process-wide gate (one per SPA bundle). */\nexport const authGate = new AuthGateCoordinator();\n\n/**\n * Run an async request; on 401, recover via AuthGate and retry once.\n * `isUnauthorized` defaults to checking `status === 401` or `statusCode === 401`.\n */\nexport async function withAuthGateRetry<T>(\n execute: () => Promise<T>,\n options?: {\n isUnauthorized?: (error: unknown) => boolean;\n /** Skip gate (e.g. refresh / sso / login endpoints). */\n bypass?: boolean;\n },\n): Promise<T> {\n if (options?.bypass) return execute();\n\n await authGate.waitIfBlocked();\n\n try {\n return await execute();\n } catch (error) {\n if (!(options?.isUnauthorized ?? defaultIsUnauthorized)(error)) throw error;\n const disposition = await authGate.handleUnauthorized(messageOf(error));\n if (disposition !== \"retry\") throw error;\n return execute();\n }\n}\n\nfunction defaultIsUnauthorized(error: unknown): boolean {\n if (!error || typeof error !== \"object\") return false;\n const e = error as { status?: number; statusCode?: number; response?: { status?: number } };\n return e.status === 401 || e.statusCode === 401 || e.response?.status === 401;\n}\n\nfunction messageOf(error: unknown): string | undefined {\n if (error instanceof Error) return error.message;\n if (error && typeof error === \"object\" && \"message\" in error) {\n const m = (error as { message?: unknown }).message;\n return typeof m === \"string\" ? m : undefined;\n }\n return undefined;\n}\n","import { createContext, useCallback, useContext, useEffect, useMemo, useState } from \"react\";\nimport {\n clearStoredSession,\n getCurrentUser,\n getStoredAccessToken,\n handleSignInCallback,\n signInPopup,\n signInRedirect,\n signOutRedirect,\n} from \"./oidc-client\";\nimport { isIdpConfigured, readIdpConfigFromEnv, type LuminaryAuthSession, type LuminaryIdpConfig } from \"./types\";\n\ninterface LuminaryAuthContextValue {\n configured: boolean;\n session: LuminaryAuthSession | null;\n accessToken: string | null;\n loading: boolean;\n login: (returnUrl?: string) => Promise<void>;\n /** Popup OIDC — keeps the opener SPA mounted. */\n loginPopup: (returnUrl?: string) => Promise<LuminaryAuthSession>;\n logout: () => Promise<void>;\n completeCallback: () => Promise<{ returnUrl?: string }>;\n refreshSession: () => Promise<void>;\n}\n\nconst LuminaryAuthContext = createContext<LuminaryAuthContextValue | null>(null);\n\nexport interface LuminaryAuthProviderProps {\n config?: Partial<LuminaryIdpConfig>;\n children: React.ReactNode;\n}\n\nexport function LuminaryAuthProvider({ config: configProp, children }: LuminaryAuthProviderProps) {\n const config = useMemo(() => configProp ?? {}, [configProp]);\n const configured = isIdpConfigured(config);\n const [session, setSession] = useState<LuminaryAuthSession | null>(null);\n const [loading, setLoading] = useState(configured);\n\n const refreshSession = useCallback(async () => {\n if (!configured) {\n setSession(null);\n setLoading(false);\n return;\n }\n setLoading(true);\n try {\n const current = await getCurrentUser(config);\n setSession(current);\n } catch {\n setSession(null);\n } finally {\n setLoading(false);\n }\n }, [config, configured]);\n\n useEffect(() => {\n void refreshSession();\n }, [refreshSession]);\n\n const login = useCallback(\n async (returnUrl?: string) => {\n if (!configured) throw new Error(\"IdP not configured\");\n await signInRedirect(config, returnUrl);\n },\n [config, configured],\n );\n\n const loginPopup = useCallback(\n async (returnUrl?: string) => {\n if (!configured) throw new Error(\"IdP not configured\");\n const { session: next } = await signInPopup(config, returnUrl);\n setSession(next);\n return next;\n },\n [config, configured],\n );\n\n const logout = useCallback(async () => {\n if (!configured) {\n clearStoredSession(config as LuminaryIdpConfig);\n setSession(null);\n return;\n }\n setSession(null);\n await signOutRedirect(config);\n }, [config, configured]);\n\n const completeCallback = useCallback(async () => {\n if (!configured) throw new Error(\"IdP not configured\");\n const { session: next, returnUrl } = await handleSignInCallback(config);\n setSession(next);\n return { returnUrl };\n }, [config, configured]);\n\n const value = useMemo<LuminaryAuthContextValue>(\n () => ({\n configured,\n session,\n accessToken: session?.accessToken ?? (configured ? getStoredAccessToken(config) : null),\n loading,\n login,\n loginPopup,\n logout,\n completeCallback,\n refreshSession,\n }),\n [configured, session, loading, login, loginPopup, logout, completeCallback, refreshSession, config],\n );\n\n return <LuminaryAuthContext.Provider value={value}>{children}</LuminaryAuthContext.Provider>;\n}\n\nexport function useLuminaryAuth(): LuminaryAuthContextValue {\n const ctx = useContext(LuminaryAuthContext);\n if (!ctx) throw new Error(\"useLuminaryAuth must be used within LuminaryAuthProvider\");\n return ctx;\n}\n\nexport { isIdpConfigured, readIdpConfigFromEnv };\nexport type { LuminaryAuthSession, LuminaryIdpConfig };\n",".panel {\n --lw-auth-theme: #3a84ff;\n --lw-auth-theme-deep: color-mix(in srgb, var(--lw-auth-theme) 72%, #000);\n width: min(100%, 400px);\n padding: 28px 28px 22px;\n border-radius: 16px;\n background: rgba(255, 255, 255, 0.96);\n color: #14212b;\n box-shadow: 0 24px 64px rgba(15, 23, 42, 0.28);\n font-family: \"Segoe UI\", \"PingFang SC\", \"Noto Sans SC\", sans-serif;\n}\n\n.brand {\n display: flex;\n gap: 14px;\n align-items: center;\n margin-bottom: 12px;\n}\n\n.logo {\n border-radius: 12px;\n display: block;\n}\n\n.product {\n margin: 0;\n font-size: 13px;\n font-weight: 650;\n letter-spacing: 0.04em;\n text-transform: uppercase;\n color: var(--lw-auth-theme);\n}\n\n.title {\n margin: 2px 0 0;\n font-size: 22px;\n font-weight: 700;\n line-height: 1.25;\n}\n\n.subtitle {\n margin: 0 0 18px;\n font-size: 14px;\n line-height: 1.5;\n color: #4b5c68;\n}\n\n.form {\n display: grid;\n gap: 10px;\n}\n\n.socialStack {\n display: flex;\n flex-wrap: wrap;\n gap: 10px;\n font-size: 12px;\n}\n\n.input {\n width: 100%;\n box-sizing: border-box;\n border: 1px solid #c9d5de;\n border-radius: 10px;\n padding: 10px 12px;\n font-size: 14px;\n outline: none;\n background: #f7fafc;\n}\n.input:focus {\n border-color: var(--lw-auth-theme);\n}\n.input:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.passwordField {\n position: relative;\n display: flex;\n align-items: center;\n}\n\n.passwordInput {\n padding-right: 42px;\n}\n\n.passwordToggle {\n position: absolute;\n right: 4px;\n top: 50%;\n transform: translateY(-50%);\n z-index: 1;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n border: none;\n border-radius: 4px;\n padding: 0;\n color: #5a6b76;\n background: transparent;\n cursor: pointer;\n}\n.passwordToggle:hover:not(:disabled) {\n color: var(--lw-auth-theme);\n background: color-mix(in srgb, var(--lw-auth-theme) 12%, transparent);\n}\n.passwordToggle:focus-visible {\n outline: 2px solid var(--lw-auth-theme);\n outline-offset: 1px;\n}\n.passwordToggle:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.primaryBtn {\n border: none;\n border-radius: 10px;\n padding: 11px 14px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: #fff;\n background: linear-gradient(135deg, var(--lw-auth-theme) 0%, var(--lw-auth-theme-deep) 100%);\n}\n.primaryBtn:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.socialBtn {\n flex: 1 1 calc(50% - 5px);\n min-width: min(140px, 100%);\n display: flex;\n align-items: center;\n justify-content: center;\n gap: 8px;\n border: 1px solid #b7c9d4;\n border-radius: 10px;\n padding: 11px 10px;\n font-size: 14px;\n font-weight: 650;\n cursor: pointer;\n color: #14212b;\n background: #fff;\n}\n.socialBtn:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.socialLogo {\n flex-shrink: 0;\n display: block;\n}\n\n.logoFallback {\n width: 18px;\n height: 18px;\n border-radius: 4px;\n background: color-mix(in srgb, var(--lw-auth-theme) 14%, #fff);\n color: var(--lw-auth-theme-deep);\n font-size: 11px;\n font-weight: 700;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex-shrink: 0;\n}\n\n.cancelBtn {\n margin-top: 10px;\n width: 100%;\n border: none;\n background: transparent;\n color: #5a6b76;\n font-size: 13px;\n cursor: pointer;\n padding: 8px;\n}\n.cancelBtn:disabled {\n opacity: 0.65;\n cursor: not-allowed;\n}\n\n.divider {\n display: flex;\n align-items: center;\n gap: 10px;\n margin: 14px 0;\n color: #90a0ab;\n}\n\n.dividerLine {\n flex: 1;\n height: 1px;\n background: #d5e0e7;\n}\n\n.dividerText {\n font-size: 12px;\n text-transform: uppercase;\n letter-spacing: 0.08em;\n}\n\n.hint {\n margin: 10px 0 0;\n font-size: 12px;\n color: #6b7c87;\n line-height: 1.45;\n}\n\n.error {\n margin: 12px 0 0;\n font-size: 13px;\n color: #b42318;\n line-height: 1.4;\n}\n\n.footer {\n margin-top: 18px;\n padding-top: 12px;\n border-top: 1px solid #e4ebf0;\n font-size: 12px;\n color: #6b7c87;\n display: flex;\n gap: 8px;\n justify-content: center;\n}\n/*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIkhlYWRsZXNzTG9naW5QYW5lbC5tb2R1bGUuc2NzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFrQkE7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBLGVBVFU7RUFVVjtFQUNBLE9BekJJO0VBMEJKO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0EsT0E3RE07OztBQWdFUjtFQUNFO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0E7OztBQUdGO0VBQ0U7RUFDQTtFQUNBO0VBQ0EsZUFsRVU7RUFtRVY7RUFDQTtFQUNBO0VBQ0EsWUEzRVE7O0FBNkVSO0VBQ0U7O0FBR0Y7RUFDRTtFQUNBOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0EsZUF2R1U7RUF3R1Y7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBOztBQUdGO0VBQ0U7RUFDQTs7QUFHRjtFQUNFO0VBQ0E7OztBQUlKO0VBQ0U7RUFDQSxlQWhJVTtFQWlJVjtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7O0FBRUE7RUFDRTtFQUNBOzs7QUFJSjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0EsZUF0SlU7RUF1SlY7RUFDQTtFQUNBO0VBQ0E7RUFDQSxPQTFLSTtFQTJLSjs7QUFFQTtFQUNFO0VBQ0E7OztBQUlKO0VBQ0U7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0EsZUEzS1U7RUE0S1Y7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBO0VBQ0E7RUFDQTtFQUNBOztBQUVBO0VBQ0U7RUFDQTs7O0FBSUo7RUFDRTtFQUNBO0VBQ0E7RUFDQTtFQUNBLE9BbE5ROzs7QUFxTlY7RUFDRTtFQUNBO0VBQ0EsWUF6Tks7OztBQTROUDtFQUNFO0VBQ0E7RUFDQTs7O0FBR0Y7RUFDRTtFQUNBO0VBQ0EsT0EzT0s7RUE0T0w7OztBQUdGO0VBQ0U7RUFDQTtFQUNBLE9BeE9PO0VBeU9QOzs7QUFHRjtFQUNFO0VBQ0E7RUFDQTtFQUNBO0VBQ0EsT0EzUEs7RUE0UEw7RUFDQTtFQUNBIiwic291cmNlc0NvbnRlbnQiOlsiJGluazogIzE0MjEyYjtcbiRtdXRlZDogIzRiNWM2ODtcbiRoaW50OiAjNmI3Yzg3O1xuJGJyYW5kOiAjM2Q2ZjhmO1xuJGJyYW5kLWRlZXA6ICMxNTQ4NWM7XG4kYnJhbmQtbWlkOiAjMWY2ZjhiO1xuJGJvcmRlcjogI2M5ZDVkZTtcbiRib3JkZXItc29mdDogI2I3YzlkNDtcbiRsaW5lOiAjZDVlMGU3O1xuJGRpdmlkZXI6ICM5MGEwYWI7XG4kc3VyZmFjZTogI2Y3ZmFmYztcbiRmYWxsYmFjay1iZzogI2U4ZWVmMjtcbiRkYW5nZXI6ICNiNDIzMTg7XG4kZm9vdGVyLWxpbmU6ICNlNGViZjA7XG4kcmFkaXVzLWxnOiAxNnB4O1xuJHJhZGl1cy1tZDogMTBweDtcbiRyYWRpdXMtc206IDRweDtcblxuLnBhbmVsIHtcbiAgLS1sdy1hdXRoLXRoZW1lOiAjM2E4NGZmO1xuICAtLWx3LWF1dGgtdGhlbWUtZGVlcDogY29sb3ItbWl4KGluIHNyZ2IsIHZhcigtLWx3LWF1dGgtdGhlbWUpIDcyJSwgIzAwMCk7XG4gIHdpZHRoOiBtaW4oMTAwJSwgNDAwcHgpO1xuICBwYWRkaW5nOiAyOHB4IDI4cHggMjJweDtcbiAgYm9yZGVyLXJhZGl1czogJHJhZGl1cy1sZztcbiAgYmFja2dyb3VuZDogcmdiYSgyNTUsIDI1NSwgMjU1LCAwLjk2KTtcbiAgY29sb3I6ICRpbms7XG4gIGJveC1zaGFkb3c6IDAgMjRweCA2NHB4IHJnYmEoMTUsIDIzLCA0MiwgMC4yOCk7XG4gIGZvbnQtZmFtaWx5OiBcIlNlZ29lIFVJXCIsIFwiUGluZ0ZhbmcgU0NcIiwgXCJOb3RvIFNhbnMgU0NcIiwgc2Fucy1zZXJpZjtcbn1cblxuLmJyYW5kIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZ2FwOiAxNHB4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBtYXJnaW4tYm90dG9tOiAxMnB4O1xufVxuXG4ubG9nbyB7XG4gIGJvcmRlci1yYWRpdXM6IDEycHg7XG4gIGRpc3BsYXk6IGJsb2NrO1xufVxuXG4ucHJvZHVjdCB7XG4gIG1hcmdpbjogMDtcbiAgZm9udC1zaXplOiAxM3B4O1xuICBmb250LXdlaWdodDogNjUwO1xuICBsZXR0ZXItc3BhY2luZzogMC4wNGVtO1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICBjb2xvcjogdmFyKC0tbHctYXV0aC10aGVtZSk7XG59XG5cbi50aXRsZSB7XG4gIG1hcmdpbjogMnB4IDAgMDtcbiAgZm9udC1zaXplOiAyMnB4O1xuICBmb250LXdlaWdodDogNzAwO1xuICBsaW5lLWhlaWdodDogMS4yNTtcbn1cblxuLnN1YnRpdGxlIHtcbiAgbWFyZ2luOiAwIDAgMThweDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBsaW5lLWhlaWdodDogMS41O1xuICBjb2xvcjogJG11dGVkO1xufVxuXG4uZm9ybSB7XG4gIGRpc3BsYXk6IGdyaWQ7XG4gIGdhcDogMTBweDtcbn1cblxuLnNvY2lhbFN0YWNrIHtcbiAgZGlzcGxheTogZmxleDtcbiAgZmxleC13cmFwOiB3cmFwO1xuICBnYXA6IDEwcHg7XG4gIGZvbnQtc2l6ZTogMTJweDtcbn1cblxuLmlucHV0IHtcbiAgd2lkdGg6IDEwMCU7XG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XG4gIGJvcmRlcjogMXB4IHNvbGlkICRib3JkZXI7XG4gIGJvcmRlci1yYWRpdXM6ICRyYWRpdXMtbWQ7XG4gIHBhZGRpbmc6IDEwcHggMTJweDtcbiAgZm9udC1zaXplOiAxNHB4O1xuICBvdXRsaW5lOiBub25lO1xuICBiYWNrZ3JvdW5kOiAkc3VyZmFjZTtcblxuICAmOmZvY3VzIHtcbiAgICBib3JkZXItY29sb3I6IHZhcigtLWx3LWF1dGgtdGhlbWUpO1xuICB9XG5cbiAgJjpkaXNhYmxlZCB7XG4gICAgb3BhY2l0eTogMC42NTtcbiAgICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xuICB9XG59XG5cbi5wYXNzd29yZEZpZWxkIHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xufVxuXG4ucGFzc3dvcmRJbnB1dCB7XG4gIHBhZGRpbmctcmlnaHQ6IDQycHg7XG59XG5cbi5wYXNzd29yZFRvZ2dsZSB7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgcmlnaHQ6IDRweDtcbiAgdG9wOiA1MCU7XG4gIHRyYW5zZm9ybTogdHJhbnNsYXRlWSgtNTAlKTtcbiAgei1pbmRleDogMTtcbiAgZGlzcGxheTogaW5saW5lLWZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICB3aWR0aDogMzZweDtcbiAgaGVpZ2h0OiAzNnB4O1xuICBib3JkZXI6IG5vbmU7XG4gIGJvcmRlci1yYWRpdXM6ICRyYWRpdXMtc207XG4gIHBhZGRpbmc6IDA7XG4gIGNvbG9yOiAjNWE2Yjc2O1xuICBiYWNrZ3JvdW5kOiB0cmFuc3BhcmVudDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuXG4gICY6aG92ZXI6bm90KDpkaXNhYmxlZCkge1xuICAgIGNvbG9yOiB2YXIoLS1sdy1hdXRoLXRoZW1lKTtcbiAgICBiYWNrZ3JvdW5kOiBjb2xvci1taXgoaW4gc3JnYiwgdmFyKC0tbHctYXV0aC10aGVtZSkgMTIlLCB0cmFuc3BhcmVudCk7XG4gIH1cblxuICAmOmZvY3VzLXZpc2libGUge1xuICAgIG91dGxpbmU6IDJweCBzb2xpZCB2YXIoLS1sdy1hdXRoLXRoZW1lKTtcbiAgICBvdXRsaW5lLW9mZnNldDogMXB4O1xuICB9XG5cbiAgJjpkaXNhYmxlZCB7XG4gICAgb3BhY2l0eTogMC42NTtcbiAgICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xuICB9XG59XG5cbi5wcmltYXJ5QnRuIHtcbiAgYm9yZGVyOiBub25lO1xuICBib3JkZXItcmFkaXVzOiAkcmFkaXVzLW1kO1xuICBwYWRkaW5nOiAxMXB4IDE0cHg7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgZm9udC13ZWlnaHQ6IDY1MDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBjb2xvcjogI2ZmZjtcbiAgYmFja2dyb3VuZDogbGluZWFyLWdyYWRpZW50KDEzNWRlZywgdmFyKC0tbHctYXV0aC10aGVtZSkgMCUsIHZhcigtLWx3LWF1dGgtdGhlbWUtZGVlcCkgMTAwJSk7XG5cbiAgJjpkaXNhYmxlZCB7XG4gICAgb3BhY2l0eTogMC42NTtcbiAgICBjdXJzb3I6IG5vdC1hbGxvd2VkO1xuICB9XG59XG5cbi5zb2NpYWxCdG4ge1xuICBmbGV4OiAxIDEgY2FsYyg1MCUgLSA1cHgpO1xuICBtaW4td2lkdGg6IG1pbigxNDBweCwgMTAwJSk7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBnYXA6IDhweDtcbiAgYm9yZGVyOiAxcHggc29saWQgJGJvcmRlci1zb2Z0O1xuICBib3JkZXItcmFkaXVzOiAkcmFkaXVzLW1kO1xuICBwYWRkaW5nOiAxMXB4IDEwcHg7XG4gIGZvbnQtc2l6ZTogMTRweDtcbiAgZm9udC13ZWlnaHQ6IDY1MDtcbiAgY3Vyc29yOiBwb2ludGVyO1xuICBjb2xvcjogJGluaztcbiAgYmFja2dyb3VuZDogI2ZmZjtcblxuICAmOmRpc2FibGVkIHtcbiAgICBvcGFjaXR5OiAwLjY1O1xuICAgIGN1cnNvcjogbm90LWFsbG93ZWQ7XG4gIH1cbn1cblxuLnNvY2lhbExvZ28ge1xuICBmbGV4LXNocmluazogMDtcbiAgZGlzcGxheTogYmxvY2s7XG59XG5cbi5sb2dvRmFsbGJhY2sge1xuICB3aWR0aDogMThweDtcbiAgaGVpZ2h0OiAxOHB4O1xuICBib3JkZXItcmFkaXVzOiAkcmFkaXVzLXNtO1xuICBiYWNrZ3JvdW5kOiBjb2xvci1taXgoaW4gc3JnYiwgdmFyKC0tbHctYXV0aC10aGVtZSkgMTQlLCAjZmZmKTtcbiAgY29sb3I6IHZhcigtLWx3LWF1dGgtdGhlbWUtZGVlcCk7XG4gIGZvbnQtc2l6ZTogMTFweDtcbiAgZm9udC13ZWlnaHQ6IDcwMDtcbiAgZGlzcGxheTogaW5saW5lLWZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xuICBmbGV4LXNocmluazogMDtcbn1cblxuLmNhbmNlbEJ0biB7XG4gIG1hcmdpbi10b3A6IDEwcHg7XG4gIHdpZHRoOiAxMDAlO1xuICBib3JkZXI6IG5vbmU7XG4gIGJhY2tncm91bmQ6IHRyYW5zcGFyZW50O1xuICBjb2xvcjogIzVhNmI3NjtcbiAgZm9udC1zaXplOiAxM3B4O1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIHBhZGRpbmc6IDhweDtcblxuICAmOmRpc2FibGVkIHtcbiAgICBvcGFjaXR5OiAwLjY1O1xuICAgIGN1cnNvcjogbm90LWFsbG93ZWQ7XG4gIH1cbn1cblxuLmRpdmlkZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBnYXA6IDEwcHg7XG4gIG1hcmdpbjogMTRweCAwO1xuICBjb2xvcjogJGRpdmlkZXI7XG59XG5cbi5kaXZpZGVyTGluZSB7XG4gIGZsZXg6IDE7XG4gIGhlaWdodDogMXB4O1xuICBiYWNrZ3JvdW5kOiAkbGluZTtcbn1cblxuLmRpdmlkZXJUZXh0IHtcbiAgZm9udC1zaXplOiAxMnB4O1xuICB0ZXh0LXRyYW5zZm9ybTogdXBwZXJjYXNlO1xuICBsZXR0ZXItc3BhY2luZzogMC4wOGVtO1xufVxuXG4uaGludCB7XG4gIG1hcmdpbjogMTBweCAwIDA7XG4gIGZvbnQtc2l6ZTogMTJweDtcbiAgY29sb3I6ICRoaW50O1xuICBsaW5lLWhlaWdodDogMS40NTtcbn1cblxuLmVycm9yIHtcbiAgbWFyZ2luOiAxMnB4IDAgMDtcbiAgZm9udC1zaXplOiAxM3B4O1xuICBjb2xvcjogJGRhbmdlcjtcbiAgbGluZS1oZWlnaHQ6IDEuNDtcbn1cblxuLmZvb3RlciB7XG4gIG1hcmdpbi10b3A6IDE4cHg7XG4gIHBhZGRpbmctdG9wOiAxMnB4O1xuICBib3JkZXItdG9wOiAxcHggc29saWQgJGZvb3Rlci1saW5lO1xuICBmb250LXNpemU6IDEycHg7XG4gIGNvbG9yOiAkaGludDtcbiAgZGlzcGxheTogZmxleDtcbiAgZ2FwOiA4cHg7XG4gIGp1c3RpZnktY29udGVudDogY2VudGVyO1xufVxuIl19 */","import { useEffect, useState, type CSSProperties, type FormEvent, type ReactNode } from \"react\";\nimport {\n LOGIN_EXPERIENCE_CAPABILITIES,\n resolveLoginExperienceAdapter,\n type ExperienceSocialConnector,\n type LoginExperienceAdapter,\n type SocialSignInRequest,\n} from \"./login-experience-adapter\";\nimport { signInPopup, signInRedirect } from \"./oidc-client\";\nimport { isIdpConfigured, type LuminaryAuthSession, type LuminaryIdpConfig } from \"./types\";\nimport styles from \"./HeadlessLoginPanel.module.scss\";\n\n/** @deprecated Prefer dynamic connectors from IdP; kept for prop typing. */\nexport type SocialProviderTarget = string;\n\nexport interface HeadlessLoginLabels {\n title?: string;\n subtitle?: string;\n identifierPlaceholder?: string;\n passwordPlaceholder?: string;\n submitPassword?: string;\n /** Hosted OIDC button shown when the adapter has no password capability. */\n submitSso?: string;\n submitGoogle?: string;\n submitGithub?: string;\n socialDivider?: string;\n hint?: string;\n cancel?: string;\n experienceUnavailable?: string;\n showPassword?: string;\n hidePassword?: string;\n}\n\nexport interface HeadlessLoginPanelProps {\n config: Partial<LuminaryIdpConfig>;\n /** Login-experience provider. Defaults to the built-in Logto adapter. */\n experienceAdapter?: LoginExperienceAdapter;\n /** Product display name shown as brand signal */\n productName: string;\n logoSrc?: string;\n labels?: HeadlessLoginLabels;\n returnUrl?: string;\n /** Prefer popup (default) for reauth; use redirect for full-page login. */\n mode?: \"popup\" | \"redirect\";\n /**\n * Show Experience social connectors (Google / GitHub / …).\n * Default `true`. Set `false` for admin / internal consoles that only allow\n * password (or enterprise SSO via IdP) — hides divider + social buttons and\n * skips fetching connectors.\n * Equivalent to `socialProviders={[]}` when false.\n */\n showSocialConnectors?: boolean;\n /**\n * Social providers (when `showSocialConnectors` is not `false`):\n * - omit / `\"auto\"` — load enabled connectors from IdP (google, github, x, …)\n * - `string[]` — only these targets (still prefers IdP logos/names when available)\n * - `[]` — hide social buttons\n */\n socialProviders?: \"auto\" | SocialProviderTarget[];\n showCancel?: boolean;\n onCancel?: () => void;\n /**\n * Called after OIDC session is obtained (popup) or before redirect navigation.\n * Products typically exchange OIDC access token → product JWT here.\n */\n onOidcSession?: (session: LuminaryAuthSession, returnUrl?: string) => Promise<void> | void;\n /** When Experience returns redirectTo, open it (default: same-tab assign). */\n onExperienceRedirect?: (redirectTo: string) => void;\n footer?: ReactNode;\n className?: string;\n style?: CSSProperties;\n /**\n * Brand accent for primary CTA / focus / product label.\n * Defaults to `#3a84ff` (DataLuminary / BlockyEdu).\n */\n themeColor?: string;\n}\n\n/** Shared default accent for product login panels. */\nexport const DEFAULT_LOGIN_THEME_COLOR = \"#3a84ff\";\n\nconst defaults: Required<HeadlessLoginLabels> = {\n title: \"Sign in\",\n subtitle: \"Use your LuminaryWorks unified account\",\n identifierPlaceholder: \"Email or username\",\n passwordPlaceholder: \"Password\",\n submitPassword: \"Sign in with password\",\n submitSso: \"Continue with unified account\",\n submitGoogle: \"Google\",\n submitGithub: \"GitHub\",\n socialDivider: \"or\",\n hint: \"Social providers open directly. Password uses your LuminaryWorks account.\",\n cancel: \"Cancel\",\n experienceUnavailable: \"Password sign-in is unavailable; use a social provider instead.\",\n showPassword: \"Show password\",\n hidePassword: \"Hide password\",\n};\n\nfunction resolveSieBase(config: Partial<LuminaryIdpConfig>): string | undefined {\n // Prefer same-origin Experience base (SPA proxies /api/.well-known) to avoid\n // cross-port CORS on local Logto. Fall back to issuer origin only when needed.\n const explicit = config.experienceApiBase?.trim();\n if (explicit) return explicit.replace(/\\/$/, \"\");\n if (config.issuer) {\n try {\n return new URL(config.issuer).origin;\n } catch {\n /* fall through */\n }\n }\n return undefined;\n}\n\nfunction labelFor(connector: ExperienceSocialConnector, labels: Required<HeadlessLoginLabels>): string {\n if (connector.target === \"google\" && labels.submitGoogle) return labels.submitGoogle;\n if (connector.target === \"github\" && labels.submitGithub) return labels.submitGithub;\n return connector.name;\n}\n\nfunction cx(...parts: Array<string | undefined | false>): string {\n return parts.filter(Boolean).join(\" \");\n}\n\nexport function HeadlessLoginPanel({\n config,\n experienceAdapter: experienceAdapterProp,\n productName,\n logoSrc,\n labels: labelsProp,\n returnUrl,\n mode = \"popup\",\n showSocialConnectors = true,\n socialProviders = \"auto\",\n showCancel,\n onCancel,\n onOidcSession,\n onExperienceRedirect,\n footer,\n className,\n style,\n themeColor = DEFAULT_LOGIN_THEME_COLOR,\n}: HeadlessLoginPanelProps) {\n const experienceAdapter = resolveLoginExperienceAdapter(experienceAdapterProp);\n const labels = { ...defaults, ...labelsProp };\n const configured = isIdpConfigured(config);\n const [identifier, setIdentifier] = useState(\"\");\n const [password, setPassword] = useState(\"\");\n const [passwordVisible, setPasswordVisible] = useState(false);\n const panelStyle: CSSProperties = {\n ...style,\n [\"--lw-auth-theme\" as string]: themeColor || DEFAULT_LOGIN_THEME_COLOR,\n };\n const [loading, setLoading] = useState<\"password\" | string | null>(null);\n const [error, setError] = useState(\"\");\n const [connectors, setConnectors] = useState<ExperienceSocialConnector[]>([]);\n const socialEnabled =\n showSocialConnectors !== false &&\n !(Array.isArray(socialProviders) && socialProviders.length === 0) &&\n experienceAdapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors) &&\n experienceAdapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn) &&\n typeof experienceAdapter.fetchSocialConnectors === \"function\" &&\n typeof experienceAdapter.createSocialSignInRequest === \"function\";\n const passwordEnabled =\n experienceAdapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn) &&\n typeof experienceAdapter.experiencePasswordSignIn === \"function\";\n\n // Browser back from IdP restores bfcache with loading still set → \"…\".\n useEffect(() => {\n const resetBusy = () => setLoading(null);\n window.addEventListener(\"pageshow\", resetBusy);\n window.addEventListener(\"popstate\", resetBusy);\n return () => {\n window.removeEventListener(\"pageshow\", resetBusy);\n window.removeEventListener(\"popstate\", resetBusy);\n };\n }, []);\n\n useEffect(() => {\n const fetchConnectors = experienceAdapter.fetchSocialConnectors;\n if (!socialEnabled || !fetchConnectors) {\n setConnectors([]);\n return;\n }\n let cancelled = false;\n const sieBase = resolveSieBase(config);\n const allowlist =\n socialProviders === \"auto\" || socialProviders === undefined\n ? null\n : new Set(socialProviders.map((t) => t.toLowerCase()));\n\n const apply = (list: ExperienceSocialConnector[]) => {\n const filtered = allowlist\n ? list.filter((c) => allowlist.has(c.target.toLowerCase()))\n : list;\n if (!cancelled) setConnectors(filtered);\n };\n\n if (!sieBase) {\n // No Experience base — do not invent Google/GitHub buttons. Fake fallbacks\n // start OIDC `direct_sign_in` and dump users on Logto `/sign-in`.\n if (!cancelled) setConnectors([]);\n return;\n }\n\n void fetchConnectors.call(experienceAdapter, { apiBase: sieBase, appId: config.clientId })\n .then((list) => {\n apply(list);\n })\n .catch(() => {\n if (!cancelled) setConnectors([]);\n });\n\n return () => {\n cancelled = true;\n };\n }, [\n config.clientId,\n config.experienceApiBase,\n config.issuer,\n experienceAdapter,\n socialEnabled,\n socialProviders,\n ]);\n\n const runOidc = async (experienceRequest?: SocialSignInRequest) => {\n if (!configured) throw new Error(\"IdP not configured\");\n if (mode === \"redirect\") {\n await signInRedirect(config, { returnUrl, ...experienceRequest });\n return;\n }\n const { session, returnUrl: next } = await signInPopup(config, {\n returnUrl,\n ...experienceRequest,\n });\n await onOidcSession?.(session, next);\n };\n\n const runSocial = async (target: string) => {\n setError(\"\");\n setLoading(target);\n try {\n if (\n !socialEnabled ||\n !experienceAdapter.capabilities.includes(\n LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn,\n ) ||\n !experienceAdapter.createSocialSignInRequest\n ) {\n throw new Error(\"Login experience does not support direct social sign-in\");\n }\n await runOidc(experienceAdapter.createSocialSignInRequest(target));\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setLoading(null);\n }\n };\n\n const runHostedOidc = async () => {\n setError(\"\");\n setLoading(\"sso\");\n try {\n await runOidc();\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setLoading(null);\n }\n };\n\n const followExperienceRedirect = (redirectTo: string) => {\n if (onExperienceRedirect) {\n onExperienceRedirect(redirectTo);\n return;\n }\n window.location.assign(redirectTo);\n };\n\n const runPassword = async (event: FormEvent) => {\n event.preventDefault();\n if (!configured) return;\n setError(\"\");\n setLoading(\"password\");\n try {\n const apiBase = config.experienceApiBase?.trim();\n if (!apiBase) {\n throw new Error(labels.experienceUnavailable);\n }\n if (\n !passwordEnabled ||\n !experienceAdapter.capabilities.includes(\n LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn,\n ) ||\n !experienceAdapter.experiencePasswordSignIn\n ) {\n throw new Error(labels.experienceUnavailable);\n }\n const result = await experienceAdapter.experiencePasswordSignIn({\n apiBase,\n identifier: identifier.trim(),\n password,\n issuer: config.issuer,\n clientId: config.clientId,\n redirectUri: config.redirectUri,\n audience: config.audience,\n scopes: config.scopes,\n returnUrl,\n });\n if (result.redirectTo) {\n // Completes the PKCE interaction from bootstrap — do NOT start a new\n // authorize (that re-opens Logto hosted /sign-in).\n followExperienceRedirect(result.redirectTo);\n return;\n }\n throw new Error(\"Experience API did not return redirectTo\");\n } catch (e) {\n setError(e instanceof Error ? e.message : String(e));\n setLoading(null);\n }\n };\n\n const busy = loading !== null;\n const showSocial = socialEnabled && connectors.length > 0;\n const showHint = Boolean(labelsProp?.hint) || showSocial;\n\n return (\n <div className={cx(styles.panel, className)} style={panelStyle}>\n <header className={styles.brand}>\n {logoSrc ? <img src={logoSrc} alt=\"\" width={48} height={48} className={styles.logo} /> : null}\n <div>\n <p className={styles.product}>{productName}</p>\n <h2 className={styles.title}>{labels.title}</h2>\n </div>\n </header>\n <p className={styles.subtitle}>{labels.subtitle}</p>\n\n {configured ? (\n <>\n {passwordEnabled ? (\n <form onSubmit={(e) => void runPassword(e)} className={styles.form}>\n <input\n type=\"text\"\n name=\"identifier\"\n autoComplete=\"username\"\n placeholder={labels.identifierPlaceholder}\n value={identifier}\n onChange={(e) => setIdentifier(e.target.value)}\n className={styles.input}\n disabled={busy}\n />\n <div className={styles.passwordField}>\n <input\n type={passwordVisible ? \"text\" : \"password\"}\n name=\"password\"\n autoComplete=\"current-password\"\n placeholder={labels.passwordPlaceholder}\n value={password}\n onChange={(e) => setPassword(e.target.value)}\n className={cx(styles.input, styles.passwordInput)}\n disabled={busy}\n />\n <button\n type=\"button\"\n className={styles.passwordToggle}\n disabled={busy}\n aria-label={passwordVisible ? labels.hidePassword : labels.showPassword}\n aria-pressed={passwordVisible}\n onClick={() => setPasswordVisible((v) => !v)}\n >\n <PasswordVisibilityIcon visible={passwordVisible} />\n </button>\n </div>\n <button type=\"submit\" className={styles.primaryBtn} disabled={busy || !identifier || !password}>\n {loading === \"password\" ? \"…\" : labels.submitPassword}\n </button>\n </form>\n ) : (\n <div className={styles.form}>\n <button\n type=\"button\"\n className={styles.primaryBtn}\n disabled={busy}\n onClick={() => void runHostedOidc()}\n >\n {loading === \"sso\" ? \"…\" : labels.submitSso}\n </button>\n </div>\n )}\n {showHint ? <p className={styles.hint}>{labels.hint}</p> : null}\n\n {showSocial ? (\n <div className={styles.divider} aria-hidden>\n <span className={styles.dividerLine} />\n <span className={styles.dividerText}>{labels.socialDivider}</span>\n <span className={styles.dividerLine} />\n </div>\n ) : null}\n {showSocial ? (\n <div className={styles.socialStack}>\n {connectors.map((connector) => (\n <button\n key={connector.id}\n type=\"button\"\n className={styles.socialBtn}\n disabled={busy}\n onClick={() => void runSocial(connector.target)}\n >\n <SocialLogo connector={connector} />\n {loading === connector.target ? \"…\" : labelFor(connector, labels)}\n </button>\n ))}\n </div>\n ) : null}\n\n </>\n ) : (\n <p className={styles.error}>IdP is not configured (issuer / clientId / redirectUri).</p>\n )}\n\n {error ? <p className={styles.error}>{error}</p> : null}\n\n {showCancel ? (\n <button type=\"button\" className={styles.cancelBtn} disabled={busy} onClick={onCancel}>\n {labels.cancel}\n </button>\n ) : null}\n\n {footer ? <footer className={styles.footer}>{footer}</footer> : null}\n </div>\n );\n}\n\nfunction SocialLogo({ connector }: { connector: ExperienceSocialConnector }) {\n if (connector.logo) {\n return <img src={connector.logo} alt=\"\" width={18} height={18} className={styles.socialLogo} />;\n }\n return (\n <span className={styles.logoFallback} aria-hidden>\n {connector.name.slice(0, 1).toUpperCase()}\n </span>\n );\n}\n\nfunction PasswordVisibilityIcon({ visible }: { visible: boolean }) {\n // Filled icons (antd Eye / EyeInvisible style) — no dependency.\n if (visible) {\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 1024 1024\" fill=\"currentColor\" aria-hidden>\n <path d=\"M942.2 486.2C847.4 286.5 704.1 186 512 186c-57.9 0-111.5 9.8-160.3 27.7l72.3 72.3C457 273.3 483.5 266 512 266c161.3 0 279.4 81.8 362.7 254-26.3 54.4-57.5 100.2-93.3 136.1l59.6 59.6C891.4 655.7 932.5 578.5 942.2 537.7a60.3 60.3 0 000-51.5zM336.6 278.6l-59.9-59.9C230.6 255.4 182.8 296.4 141.9 348.1 95.4 412.1 64.6 486.5 51.8 512a60.3 60.3 0 000 51.5C115.3 719.5 224.6 814.8 365.4 860.1l72.5-72.5C353.6 761.6 286.3 698.3 241.3 612.5 220.6 573.1 205 528.6 194.5 486.2c24.5-50.4 55.1-92.1 90.8-124.9l51.3-51.3zM606.6 556.6A112 112 0 01467.4 417.4L606.6 556.6zM508 624c-26.5 0-50.9-9.2-70.2-24.6l-59.9 59.9A175.3 175.3 0 00508 688c97.2 0 176-78.8 176-176 0-26.5-9.2-50.9-24.6-70.2l-59.9 59.9c15.4 19.3 24.6 43.7 24.6 70.2 0 61.9-50.1 112-112 112zM880 112L112 880l48 48 768-768z\" />\n </svg>\n );\n }\n return (\n <svg width=\"18\" height=\"18\" viewBox=\"0 0 1024 1024\" fill=\"currentColor\" aria-hidden>\n <path d=\"M942.2 486.2C847.4 286.5 704.1 186 512 186c-192.2 0-335.4 100.5-430.2 300.3a60.3 60.3 0 000 51.5C176.6 737.5 319.9 838 512 838c192.2 0 335.4-100.5 430.2-300.3a60.3 60.3 0 000-51.5zM512 766c-161.3 0-279.4-81.8-362.7-254C232.6 339.8 350.7 258 512 258c161.3 0 279.4 81.8 362.7 254C791.5 684.2 673.4 766 512 766z\" />\n <path d=\"M508 336c-97.2 0-176 78.8-176 176s78.8 176 176 176 176-78.8 176-176-78.8-176-176-176zm0 288c-61.9 0-112-50.1-112-112s50.1-112 112-112 112 50.1 112 112-50.1 112-112 112z\" />\n </svg>\n );\n}\n","import { useSyncExternalStore, type CSSProperties, type ReactNode } from \"react\";\nimport { authGate } from \"./auth-gate\";\nimport { HeadlessLoginPanel, type HeadlessLoginLabels } from \"./HeadlessLoginPanel\";\nimport type { LuminaryAuthSession, LuminaryIdpConfig } from \"./types\";\n\nexport interface ReauthOverlayProps {\n config: Partial<LuminaryIdpConfig>;\n productName: string;\n logoSrc?: string;\n labels?: HeadlessLoginLabels;\n returnUrl?: string;\n /** Brand accent forwarded to HeadlessLoginPanel (default `#3a84ff`). */\n themeColor?: string;\n /** Exchange OIDC token / persist product session, then AuthGate completes. */\n onOidcSession: (session: LuminaryAuthSession, returnUrl?: string) => Promise<void> | void;\n /** Optional custom body instead of HeadlessLoginPanel */\n children?: ReactNode;\n /** Allow dismiss → cancelReauth (default true for mid-session; false for hard gate). */\n dismissible?: boolean;\n onDismiss?: () => void;\n}\n\n/**\n * Full-viewport soft gate shown while AuthGate phase is `reauth` (or `refreshing` spinner).\n * Does not iframe the IdP — uses Headless panel + OIDC popup.\n */\nexport function ReauthOverlay({\n config,\n productName,\n logoSrc,\n labels,\n returnUrl,\n themeColor,\n onOidcSession,\n children,\n dismissible = true,\n onDismiss,\n}: ReauthOverlayProps) {\n const snapshot = useSyncExternalStore(authGate.subscribe, authGate.getSnapshot, authGate.getSnapshot);\n\n if (snapshot.phase === \"idle\") return null;\n\n const resolvedReturnUrl =\n returnUrl ??\n (() => {\n if (typeof window === \"undefined\") return undefined;\n const hash = window.location.hash.replace(/^#/, \"\");\n if (!hash || hash.startsWith(\"/login\") || hash.startsWith(\"/auth/\")) return undefined;\n return hash.startsWith(\"/\") ? hash : `/${hash}`;\n })();\n\n const handleSession = async (session: LuminaryAuthSession, next?: string) => {\n await onOidcSession(session, next);\n authGate.completeReauth();\n };\n\n const handleCancel = () => {\n onDismiss?.();\n authGate.cancelReauth(\"cancelled\");\n };\n\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={productName}\n style={backdropStyle}\n onClick={dismissible ? handleCancel : undefined}\n >\n <div style={centerStyle} onClick={(e) => e.stopPropagation()}>\n {snapshot.phase === \"refreshing\" ? (\n <div style={spinnerCardStyle}>\n <div style={spinnerStyle} />\n <p style={{ margin: 0, color: \"#e8eef2\" }}>Refreshing session…</p>\n </div>\n ) : children ? (\n children\n ) : (\n <HeadlessLoginPanel\n config={config}\n productName={productName}\n logoSrc={logoSrc}\n themeColor={themeColor}\n labels={{\n title: labels?.title ?? \"Session expired\",\n subtitle: labels?.subtitle ?? \"Sign in again to keep working — this page will not reload.\",\n ...labels,\n }}\n returnUrl={resolvedReturnUrl}\n mode=\"popup\"\n showCancel={dismissible}\n onCancel={handleCancel}\n onOidcSession={handleSession}\n />\n )}\n </div>\n </div>\n );\n}\n\nconst backdropStyle: CSSProperties = {\n position: \"fixed\",\n inset: 0,\n zIndex: 10000,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: 24,\n background:\n \"radial-gradient(1200px 600px at 20% 10%, rgba(56, 120, 150, 0.35), transparent 55%), rgba(10, 18, 24, 0.72)\",\n backdropFilter: \"blur(6px)\",\n};\n\nconst centerStyle: CSSProperties = {\n width: \"min(100%, 420px)\",\n};\n\nconst spinnerCardStyle: CSSProperties = {\n display: \"grid\",\n justifyItems: \"center\",\n gap: 14,\n padding: 28,\n borderRadius: 16,\n background: \"rgba(20, 32, 40, 0.88)\",\n};\n\nconst spinnerStyle: CSSProperties = {\n width: 36,\n height: 36,\n borderRadius: \"50%\",\n border: \"3px solid rgba(255,255,255,0.2)\",\n borderTopColor: \"#7ec8e3\",\n animation: \"luminary-auth-spin 0.8s linear infinite\",\n};\n\n// Inject keyframes once\nif (typeof document !== \"undefined\" && !document.getElementById(\"luminary-auth-spin-style\")) {\n const style = document.createElement(\"style\");\n style.id = \"luminary-auth-spin-style\";\n style.textContent = `@keyframes luminary-auth-spin { to { transform: rotate(360deg); } }`;\n document.head.appendChild(style);\n}\n","import { createContext, useContext, useEffect, useMemo, type ReactNode } from \"react\";\nimport { useSyncExternalStore } from \"react\";\nimport { authGate, type AuthGateConfig, type AuthGateSnapshot } from \"./auth-gate\";\nimport { ReauthOverlay, type ReauthOverlayProps } from \"./ReauthOverlay\";\nimport type { LuminaryAuthSession, LuminaryIdpConfig } from \"./types\";\n\ninterface AuthGateContextValue {\n snapshot: AuthGateSnapshot;\n requestReauth: (message?: string) => Promise<\"retry\" | \"fail\">;\n completeReauth: () => void;\n cancelReauth: (message?: string) => void;\n}\n\nconst AuthGateContext = createContext<AuthGateContextValue | null>(null);\n\nexport interface AuthGateProviderProps extends AuthGateConfig {\n children: ReactNode;\n /** When set, mounts {@link ReauthOverlay} automatically. */\n overlay?: Omit<ReauthOverlayProps, \"onOidcSession\"> & {\n onOidcSession: (session: LuminaryAuthSession, returnUrl?: string) => Promise<void> | void;\n config: Partial<LuminaryIdpConfig>;\n };\n}\n\nexport function AuthGateProvider({\n children,\n tryRefresh,\n onReauthRequired,\n onSettled,\n overlay,\n}: AuthGateProviderProps) {\n useEffect(() => {\n authGate.configure({ tryRefresh, onReauthRequired, onSettled });\n }, [tryRefresh, onReauthRequired, onSettled]);\n\n const snapshot = useSyncExternalStore(authGate.subscribe, authGate.getSnapshot, authGate.getSnapshot);\n\n const value = useMemo<AuthGateContextValue>(\n () => ({\n snapshot,\n requestReauth: (message?: string) => authGate.requestReauth(message),\n completeReauth: () => authGate.completeReauth(),\n cancelReauth: (message?: string) => authGate.cancelReauth(message),\n }),\n [snapshot],\n );\n\n return (\n <AuthGateContext.Provider value={value}>\n {children}\n {overlay ? <ReauthOverlay {...overlay} /> : null}\n </AuthGateContext.Provider>\n );\n}\n\nexport function useAuthGate(): AuthGateContextValue {\n const ctx = useContext(AuthGateContext);\n if (!ctx) throw new Error(\"useAuthGate must be used within AuthGateProvider\");\n return ctx;\n}\n\n/** Optional hook — returns null outside provider (for shared API helpers). */\nexport function useAuthGateOptional(): AuthGateContextValue | null {\n return useContext(AuthGateContext);\n}\n","export interface PostLoginPathOptions {\n /** sessionStorage key (product-scoped), e.g. `dv:postLoginPath` */\n storageKey: string;\n /** Default destination when nothing remembered */\n defaultPath?: string;\n /** Extra paths that must not be used as return targets */\n unsafePrefixes?: string[];\n}\n\nconst DEFAULT_UNSAFE = [\"/login\", \"/auth\", \"/exception\"];\n\nfunction normalizeAppPath(path: string, fallback: string): string {\n const raw = path.replace(/^#/, \"\").trim();\n if (!raw) return fallback.startsWith(\"/\") ? fallback : `/${fallback}`;\n return raw.startsWith(\"/\") ? raw : `/${raw}`;\n}\n\nfunction isUnsafeReturnPath(path: string, unsafePrefixes: string[], fallback: string): boolean {\n const p = normalizeAppPath(path, fallback);\n if (p === \"/\") return true;\n return unsafePrefixes.some((prefix) => p === prefix || p.startsWith(`${prefix}/`) || p.startsWith(prefix));\n}\n\n/**\n * sessionStorage helpers for OIDC redirect return paths.\n * Product-specific ACL checks (e.g. 403 fallback) stay in the product.\n */\nexport function createPostLoginPathHelpers(options: PostLoginPathOptions) {\n const storageKey = options.storageKey;\n const defaultPath = options.defaultPath?.startsWith(\"/\")\n ? options.defaultPath\n : `/${options.defaultPath || \"home\"}`;\n const unsafePrefixes = [...DEFAULT_UNSAFE, ...(options.unsafePrefixes || [])];\n\n function rememberPostLoginPath(path: string): void {\n const normalized = normalizeAppPath(path, defaultPath);\n if (isUnsafeReturnPath(normalized, unsafePrefixes, defaultPath)) return;\n try {\n sessionStorage.setItem(storageKey, normalized);\n } catch {\n /* ignore */\n }\n }\n\n function peekPostLoginPath(): string | undefined {\n try {\n const v = sessionStorage.getItem(storageKey);\n if (!v || isUnsafeReturnPath(v, unsafePrefixes, defaultPath)) return undefined;\n return normalizeAppPath(v, defaultPath);\n } catch {\n return undefined;\n }\n }\n\n function consumePostLoginPath(fallback = defaultPath): string {\n const remembered = peekPostLoginPath();\n try {\n sessionStorage.removeItem(storageKey);\n } catch {\n /* ignore */\n }\n return remembered ?? normalizeAppPath(fallback, defaultPath);\n }\n\n return {\n rememberPostLoginPath,\n peekPostLoginPath,\n consumePostLoginPath,\n normalizeAppPath: (path: string) => normalizeAppPath(path, defaultPath),\n isUnsafeReturnPath: (path: string) => isUnsafeReturnPath(path, unsafePrefixes, defaultPath),\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@luminaryworks/auth-react",
3
- "version": "0.3.2",
3
+ "version": "0.4.1",
4
4
  "license": "Polyform-Noncommercial-1.0.0",
5
5
  "description": "LuminaryWorks unified OIDC SPA client (Logto / enterprise IdP)",
6
6
  "repository": {