@luminaryworks/auth-react 0.3.2 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -36,9 +36,221 @@ function readIdpConfigFromEnv(env) {
36
36
  scopes: env.VITE_IDP_SCOPES ?? env.PUBLIC_IDP_SCOPES ?? "openid profile email offline_access",
37
37
  audience: env.VITE_IDP_AUDIENCE ?? env.PUBLIC_IDP_AUDIENCE,
38
38
  tokenStorageKey: env.VITE_IDP_TOKEN_KEY ?? "luminary_access_token",
39
- experienceApiBase: resolveExperienceApiBase(env)
39
+ experienceApiBase: resolveExperienceApiBase(env),
40
+ iamProvider: env.VITE_IAM_PROVIDER ?? env.PUBLIC_IAM_PROVIDER ?? env.IAM_PROVIDER ?? env.IDP_MODE
40
41
  };
41
42
  }
43
+
44
+ // src/hosted-oidc-experience-adapter.ts
45
+ var HostedOidcExperienceAdapter = class {
46
+ constructor(provider = "hosted") {
47
+ this.provider = provider;
48
+ }
49
+ provider;
50
+ capabilities = [];
51
+ };
52
+
53
+ // src/login-experience-adapter.ts
54
+ var LOGIN_EXPERIENCE_CAPABILITIES = {
55
+ passwordSignIn: "password-sign-in",
56
+ socialConnectors: "social-connectors",
57
+ socialDirectSignIn: "social-direct-sign-in"
58
+ };
59
+ var HOSTED_LOGIN_PROVIDERS = /* @__PURE__ */ new Set(["hosted", "oidc", "external_oidc", "zitadel"]);
60
+ function normalizeLoginExperienceProvider(provider) {
61
+ const key = provider.trim().toLowerCase();
62
+ if (!key || key === "logto") return "logto";
63
+ if (HOSTED_LOGIN_PROVIDERS.has(key)) return "hosted";
64
+ throw new Error(
65
+ `Unknown login experience provider "${provider}". Shipped: logto (default). Hosted OIDC: oidc / hosted / zitadel.`
66
+ );
67
+ }
68
+ function createLoginExperienceAdapter(provider = "logto") {
69
+ const kind = normalizeLoginExperienceProvider(provider);
70
+ if (kind === "logto") return new LogtoExperienceAdapter();
71
+ return new HostedOidcExperienceAdapter(provider.trim().toLowerCase() || "hosted");
72
+ }
73
+ var adapterCache = /* @__PURE__ */ new Map();
74
+ function resolveLoginExperienceAdapter(adapter, iamProvider) {
75
+ if (adapter) return adapter;
76
+ const key = iamProvider?.trim() || "logto";
77
+ const cached = adapterCache.get(key);
78
+ if (cached) return cached;
79
+ const created = createLoginExperienceAdapter(key);
80
+ adapterCache.set(key, created);
81
+ return created;
82
+ }
83
+ function resolveLoginExperienceProviderFromEnv(env = {}) {
84
+ return env.VITE_IAM_PROVIDER ?? env.PUBLIC_IAM_PROVIDER ?? env.IAM_PROVIDER ?? env.IDP_MODE ?? "logto";
85
+ }
86
+
87
+ // src/logto-experience-adapter.ts
88
+ function experienceUrl(apiBase, path) {
89
+ return `${apiBase.replace(/\/$/, "")}/api/experience${path}`;
90
+ }
91
+ async function experienceFetch(apiBase, path, init) {
92
+ const res = await fetch(experienceUrl(apiBase, path), {
93
+ credentials: "include",
94
+ ...init,
95
+ headers: {
96
+ "Content-Type": "application/json",
97
+ Accept: "application/json",
98
+ ...init.headers ?? {}
99
+ }
100
+ });
101
+ const text = await res.text();
102
+ let data = null;
103
+ if (text) {
104
+ try {
105
+ data = JSON.parse(text);
106
+ } catch {
107
+ data = text;
108
+ }
109
+ }
110
+ if (!res.ok) {
111
+ const msg = data && typeof data === "object" && data !== null && "message" in data ? String(data.message) : `Experience API ${res.status}`;
112
+ throw new Error(msg);
113
+ }
114
+ return data;
115
+ }
116
+ function guessIdentifierType(identifier) {
117
+ if (identifier.includes("@")) return "email";
118
+ if (/^\+?\d{6,}$/.test(identifier.trim())) return "phone";
119
+ return "username";
120
+ }
121
+ function sameOriginAuthorizeUrl(authorizeUrl, apiBase) {
122
+ const u = new URL(authorizeUrl);
123
+ const base = new URL(apiBase);
124
+ if (u.origin === base.origin) return authorizeUrl;
125
+ return `${base.origin}${u.pathname}${u.search}${u.hash}`;
126
+ }
127
+ async function bootstrapOidcInteraction(input) {
128
+ if (!input.issuer || !input.clientId || !input.redirectUri) return;
129
+ if (typeof document === "undefined") return;
130
+ const config = {
131
+ issuer: input.issuer,
132
+ clientId: input.clientId,
133
+ redirectUri: input.redirectUri,
134
+ audience: input.audience,
135
+ scopes: input.scopes,
136
+ experienceApiBase: input.apiBase
137
+ };
138
+ const signinUrl = await prepareSignInRequestUrl(config, {
139
+ returnUrl: input.returnUrl
140
+ });
141
+ const authorizeUrl = sameOriginAuthorizeUrl(signinUrl, input.apiBase);
142
+ await new Promise((resolve) => {
143
+ const iframe = document.createElement("iframe");
144
+ iframe.setAttribute("aria-hidden", "true");
145
+ iframe.tabIndex = -1;
146
+ iframe.style.cssText = "position:absolute;width:0;height:0;border:0;visibility:hidden";
147
+ let settled = false;
148
+ const finish = () => {
149
+ if (settled) return;
150
+ settled = true;
151
+ iframe.remove();
152
+ resolve();
153
+ };
154
+ iframe.addEventListener("load", () => {
155
+ window.setTimeout(finish, 400);
156
+ });
157
+ iframe.src = authorizeUrl;
158
+ document.body.appendChild(iframe);
159
+ window.setTimeout(finish, 2500);
160
+ });
161
+ }
162
+ function createLogtoDirectSignInRequest(directSignIn) {
163
+ return { extraQueryParams: { direct_sign_in: directSignIn } };
164
+ }
165
+ var LogtoExperienceAdapter = class {
166
+ provider = "logto";
167
+ capabilities = [
168
+ LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn,
169
+ LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors,
170
+ LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn
171
+ ];
172
+ async experiencePasswordSignIn(input) {
173
+ const { apiBase, identifier, password } = input;
174
+ await bootstrapOidcInteraction(input);
175
+ const primary = input.identifierType ?? guessIdentifierType(identifier);
176
+ const alternates = primary === "phone" ? [primary] : primary === "email" ? ["email", "username"] : ["username", "email"];
177
+ let lastError;
178
+ for (const identifierType of alternates) {
179
+ try {
180
+ await experienceFetch(apiBase, "", {
181
+ method: "PUT",
182
+ body: JSON.stringify({ interactionEvent: "SignIn" })
183
+ });
184
+ const verified = await experienceFetch(
185
+ apiBase,
186
+ "/verification/password",
187
+ {
188
+ method: "POST",
189
+ body: JSON.stringify({
190
+ identifier: { type: identifierType, value: identifier },
191
+ password
192
+ })
193
+ }
194
+ );
195
+ const verificationId = verified?.verificationId;
196
+ if (!verificationId) {
197
+ throw new Error("Experience API did not return verificationId");
198
+ }
199
+ await experienceFetch(apiBase, "/identification", {
200
+ method: "POST",
201
+ body: JSON.stringify({ verificationId })
202
+ });
203
+ const submitted = await experienceFetch(
204
+ apiBase,
205
+ "/submit",
206
+ {
207
+ method: "POST",
208
+ body: JSON.stringify({})
209
+ }
210
+ );
211
+ return { redirectTo: submitted?.redirectTo, raw: submitted };
212
+ } catch (error) {
213
+ lastError = error instanceof Error ? error : new Error(String(error));
214
+ }
215
+ }
216
+ throw lastError ?? new Error("Experience password sign-in failed");
217
+ }
218
+ async fetchSocialConnectors(input) {
219
+ const url = new URL(`${input.apiBase.replace(/\/$/, "")}/api/.well-known/sign-in-exp`);
220
+ if (input.appId?.trim()) url.searchParams.set("appId", input.appId.trim());
221
+ const res = await fetch(url.toString(), {
222
+ // Public metadata — omit cookies so browsers do not require credentialed CORS.
223
+ credentials: "omit",
224
+ headers: { Accept: "application/json" }
225
+ });
226
+ if (!res.ok) {
227
+ throw new Error(`sign-in-exp ${res.status}`);
228
+ }
229
+ const data = await res.json();
230
+ return (data.socialConnectors ?? []).filter(
231
+ (connector) => Boolean(connector?.id && connector?.target)
232
+ ).map((connector) => ({
233
+ id: connector.id,
234
+ target: connector.target,
235
+ name: localizeName(connector.name) || titleCase(connector.target),
236
+ logo: connector.logo
237
+ }));
238
+ }
239
+ createSocialSignInRequest(target) {
240
+ return createLogtoDirectSignInRequest(`social:${target}`);
241
+ }
242
+ };
243
+ function localizeName(name) {
244
+ if (!name) return "";
245
+ if (typeof name === "string") return name;
246
+ return name["zh-CN"] || name.en || Object.values(name)[0] || "";
247
+ }
248
+ function titleCase(target) {
249
+ if (!target) return "";
250
+ return target.charAt(0).toUpperCase() + target.slice(1);
251
+ }
252
+
253
+ // src/oidc-client.ts
42
254
  var manager = null;
43
255
  function storageKey(config) {
44
256
  return config.tokenStorageKey ?? "luminary_access_token";
@@ -95,9 +307,14 @@ function resetUserManager() {
95
307
  function signInArgs(config, options) {
96
308
  const normalized = typeof options === "string" ? { returnUrl: options } : options ?? {};
97
309
  const resource = config.audience?.trim();
98
- const extraQueryParams = {};
310
+ const extraQueryParams = { ...normalized.extraQueryParams };
99
311
  if (resource) extraQueryParams.resource = resource;
100
- if (normalized.directSignIn) extraQueryParams.direct_sign_in = normalized.directSignIn;
312
+ if (normalized.directSignIn) {
313
+ Object.assign(
314
+ extraQueryParams,
315
+ createLogtoDirectSignInRequest(normalized.directSignIn).extraQueryParams
316
+ );
317
+ }
101
318
  return {
102
319
  state: normalized.returnUrl ? { returnUrl: normalized.returnUrl } : void 0,
103
320
  extraQueryParams: Object.keys(extraQueryParams).length ? extraQueryParams : void 0
@@ -189,151 +406,19 @@ async function getCurrentUser(config) {
189
406
  }
190
407
 
191
408
  // 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);
409
+ function experiencePasswordSignIn(input) {
410
+ const adapter = resolveLoginExperienceAdapter();
411
+ if (!adapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn) || !adapter.experiencePasswordSignIn) {
412
+ return Promise.reject(new Error("Login experience does not support password sign-in"));
217
413
  }
218
- return data;
414
+ return adapter.experiencePasswordSignIn(input);
219
415
  }
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
- }
305
- }
306
- throw lastError ?? new Error("Experience password sign-in failed");
307
- }
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}`);
416
+ function fetchSocialConnectors(input) {
417
+ const adapter = resolveLoginExperienceAdapter();
418
+ if (!adapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.socialConnectors) || !adapter.fetchSocialConnectors) {
419
+ return Promise.reject(new Error("Login experience does not support social connectors"));
318
420
  }
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);
421
+ return adapter.fetchSocialConnectors(input);
337
422
  }
338
423
 
339
424
  // src/auth-gate.ts
@@ -596,6 +681,7 @@ function cx(...parts) {
596
681
  }
597
682
  function HeadlessLoginPanel({
598
683
  config,
684
+ experienceAdapter: experienceAdapterProp,
599
685
  productName,
600
686
  logoSrc,
601
687
  labels: labelsProp,
@@ -612,6 +698,10 @@ function HeadlessLoginPanel({
612
698
  style,
613
699
  themeColor = DEFAULT_LOGIN_THEME_COLOR
614
700
  }) {
701
+ const experienceAdapter = resolveLoginExperienceAdapter(
702
+ experienceAdapterProp,
703
+ config.iamProvider
704
+ );
615
705
  const labels = { ...defaults, ...labelsProp };
616
706
  const configured = isIdpConfigured(config);
617
707
  const [identifier, setIdentifier] = react.useState("");
@@ -624,7 +714,8 @@ function HeadlessLoginPanel({
624
714
  const [loading, setLoading] = react.useState(null);
625
715
  const [error, setError] = react.useState("");
626
716
  const [connectors, setConnectors] = react.useState([]);
627
- const socialEnabled = showSocialConnectors !== false && !(Array.isArray(socialProviders) && socialProviders.length === 0);
717
+ 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";
718
+ const passwordEnabled = experienceAdapter.capabilities.includes(LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn) && typeof experienceAdapter.experiencePasswordSignIn === "function";
628
719
  react.useEffect(() => {
629
720
  const resetBusy = () => setLoading(null);
630
721
  window.addEventListener("pageshow", resetBusy);
@@ -635,7 +726,8 @@ function HeadlessLoginPanel({
635
726
  };
636
727
  }, []);
637
728
  react.useEffect(() => {
638
- if (!socialEnabled) {
729
+ const fetchConnectors = experienceAdapter.fetchSocialConnectors;
730
+ if (!socialEnabled || !fetchConnectors) {
639
731
  setConnectors([]);
640
732
  return;
641
733
  }
@@ -650,7 +742,7 @@ function HeadlessLoginPanel({
650
742
  if (!cancelled) setConnectors([]);
651
743
  return;
652
744
  }
653
- void fetchSocialConnectors({ apiBase: sieBase, appId: config.clientId }).then((list) => {
745
+ void fetchConnectors.call(experienceAdapter, { apiBase: sieBase, appId: config.clientId }).then((list) => {
654
746
  apply(list);
655
747
  }).catch(() => {
656
748
  if (!cancelled) setConnectors([]);
@@ -658,21 +750,46 @@ function HeadlessLoginPanel({
658
750
  return () => {
659
751
  cancelled = true;
660
752
  };
661
- }, [config.clientId, config.experienceApiBase, config.issuer, socialEnabled, socialProviders]);
662
- const runOidc = async (directSignIn) => {
753
+ }, [
754
+ config.clientId,
755
+ config.experienceApiBase,
756
+ config.issuer,
757
+ experienceAdapter,
758
+ socialEnabled,
759
+ socialProviders
760
+ ]);
761
+ const runOidc = async (experienceRequest) => {
663
762
  if (!configured) throw new Error("IdP not configured");
664
763
  if (mode === "redirect") {
665
- await signInRedirect(config, { returnUrl, directSignIn });
764
+ await signInRedirect(config, { returnUrl, ...experienceRequest });
666
765
  return;
667
766
  }
668
- const { session, returnUrl: next } = await signInPopup(config, { returnUrl, directSignIn });
767
+ const { session, returnUrl: next } = await signInPopup(config, {
768
+ returnUrl,
769
+ ...experienceRequest
770
+ });
669
771
  await onOidcSession?.(session, next);
670
772
  };
671
773
  const runSocial = async (target) => {
672
774
  setError("");
673
775
  setLoading(target);
674
776
  try {
675
- await runOidc(`social:${target}`);
777
+ if (!socialEnabled || !experienceAdapter.capabilities.includes(
778
+ LOGIN_EXPERIENCE_CAPABILITIES.socialDirectSignIn
779
+ ) || !experienceAdapter.createSocialSignInRequest) {
780
+ throw new Error("Login experience does not support direct social sign-in");
781
+ }
782
+ await runOidc(experienceAdapter.createSocialSignInRequest(target));
783
+ } catch (e) {
784
+ setError(e instanceof Error ? e.message : String(e));
785
+ setLoading(null);
786
+ }
787
+ };
788
+ const runHostedOidc = async () => {
789
+ setError("");
790
+ setLoading("sso");
791
+ try {
792
+ await runOidc();
676
793
  } catch (e) {
677
794
  setError(e instanceof Error ? e.message : String(e));
678
795
  setLoading(null);
@@ -695,7 +812,12 @@ function HeadlessLoginPanel({
695
812
  if (!apiBase) {
696
813
  throw new Error(labels.experienceUnavailable);
697
814
  }
698
- const result = await experiencePasswordSignIn({
815
+ if (!passwordEnabled || !experienceAdapter.capabilities.includes(
816
+ LOGIN_EXPERIENCE_CAPABILITIES.passwordSignIn
817
+ ) || !experienceAdapter.experiencePasswordSignIn) {
818
+ throw new Error(labels.experienceUnavailable);
819
+ }
820
+ const result = await experienceAdapter.experiencePasswordSignIn({
699
821
  apiBase,
700
822
  identifier: identifier.trim(),
701
823
  password,
@@ -729,7 +851,7 @@ function HeadlessLoginPanel({
729
851
  ] }),
730
852
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: HeadlessLoginPanel_module_default.subtitle, children: labels.subtitle }),
731
853
  configured ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
732
- /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => void runPassword(e), className: HeadlessLoginPanel_module_default.form, children: [
854
+ passwordEnabled ? /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: (e) => void runPassword(e), className: HeadlessLoginPanel_module_default.form, children: [
733
855
  /* @__PURE__ */ jsxRuntime.jsx(
734
856
  "input",
735
857
  {
@@ -771,7 +893,16 @@ function HeadlessLoginPanel({
771
893
  )
772
894
  ] }),
773
895
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: HeadlessLoginPanel_module_default.primaryBtn, disabled: busy || !identifier || !password, children: loading === "password" ? "\u2026" : labels.submitPassword })
774
- ] }),
896
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: HeadlessLoginPanel_module_default.form, children: /* @__PURE__ */ jsxRuntime.jsx(
897
+ "button",
898
+ {
899
+ type: "button",
900
+ className: HeadlessLoginPanel_module_default.primaryBtn,
901
+ disabled: busy,
902
+ onClick: () => void runHostedOidc(),
903
+ children: loading === "sso" ? "\u2026" : labels.submitSso
904
+ }
905
+ ) }),
775
906
  showHint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: HeadlessLoginPanel_module_default.hint, children: labels.hint }) : null,
776
907
  showSocial ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: HeadlessLoginPanel_module_default.divider, "aria-hidden": true, children: [
777
908
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: HeadlessLoginPanel_module_default.dividerLine }),
@@ -998,10 +1129,15 @@ function createPostLoginPathHelpers(options) {
998
1129
  exports.AuthGateProvider = AuthGateProvider;
999
1130
  exports.DEFAULT_LOGIN_THEME_COLOR = DEFAULT_LOGIN_THEME_COLOR;
1000
1131
  exports.HeadlessLoginPanel = HeadlessLoginPanel;
1132
+ exports.HostedOidcExperienceAdapter = HostedOidcExperienceAdapter;
1133
+ exports.LOGIN_EXPERIENCE_CAPABILITIES = LOGIN_EXPERIENCE_CAPABILITIES;
1134
+ exports.LogtoExperienceAdapter = LogtoExperienceAdapter;
1001
1135
  exports.LuminaryAuthProvider = LuminaryAuthProvider;
1002
1136
  exports.ReauthOverlay = ReauthOverlay;
1003
1137
  exports.authGate = authGate;
1004
1138
  exports.clearStoredSession = clearStoredSession;
1139
+ exports.createLoginExperienceAdapter = createLoginExperienceAdapter;
1140
+ exports.createLogtoDirectSignInRequest = createLogtoDirectSignInRequest;
1005
1141
  exports.createPostLoginPathHelpers = createPostLoginPathHelpers;
1006
1142
  exports.createUserManager = createUserManager;
1007
1143
  exports.experiencePasswordSignIn = experiencePasswordSignIn;
@@ -1017,6 +1153,8 @@ exports.readIdpConfigFromEnv = readIdpConfigFromEnv;
1017
1153
  exports.resetUserManager = resetUserManager;
1018
1154
  exports.resolveExperienceApiBase = resolveExperienceApiBase;
1019
1155
  exports.resolveIssuer = resolveIssuer;
1156
+ exports.resolveLoginExperienceAdapter = resolveLoginExperienceAdapter;
1157
+ exports.resolveLoginExperienceProviderFromEnv = resolveLoginExperienceProviderFromEnv;
1020
1158
  exports.sameOriginAuthorizeUrl = sameOriginAuthorizeUrl;
1021
1159
  exports.signInPopup = signInPopup;
1022
1160
  exports.signInRedirect = signInRedirect;