@luminaryworks/auth-react 0.3.1 → 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/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);
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"));
217
388
  }
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";
389
+ return adapter.experiencePasswordSignIn(input);
224
390
  }
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}`);
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
@@ -575,10 +635,6 @@ var defaults = {
575
635
  showPassword: "Show password",
576
636
  hidePassword: "Hide password"
577
637
  };
578
- var FALLBACK_SOCIAL = [
579
- { id: "google", target: "google", name: "Google" },
580
- { id: "github", target: "github", name: "GitHub" }
581
- ];
582
638
  function resolveSieBase(config) {
583
639
  const explicit = config.experienceApiBase?.trim();
584
640
  if (explicit) return explicit.replace(/\/$/, "");
@@ -600,6 +656,7 @@ function cx(...parts) {
600
656
  }
601
657
  function HeadlessLoginPanel({
602
658
  config,
659
+ experienceAdapter: experienceAdapterProp,
603
660
  productName,
604
661
  logoSrc,
605
662
  labels: labelsProp,
@@ -616,6 +673,7 @@ function HeadlessLoginPanel({
616
673
  style,
617
674
  themeColor = DEFAULT_LOGIN_THEME_COLOR
618
675
  }) {
676
+ const experienceAdapter = resolveLoginExperienceAdapter(experienceAdapterProp);
619
677
  const labels = { ...defaults, ...labelsProp };
620
678
  const configured = isIdpConfigured(config);
621
679
  const [identifier, setIdentifier] = react.useState("");
@@ -628,7 +686,8 @@ function HeadlessLoginPanel({
628
686
  const [loading, setLoading] = react.useState(null);
629
687
  const [error, setError] = react.useState("");
630
688
  const [connectors, setConnectors] = react.useState([]);
631
- 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";
632
691
  react.useEffect(() => {
633
692
  const resetBusy = () => setLoading(null);
634
693
  window.addEventListener("pageshow", resetBusy);
@@ -639,7 +698,8 @@ function HeadlessLoginPanel({
639
698
  };
640
699
  }, []);
641
700
  react.useEffect(() => {
642
- if (!socialEnabled) {
701
+ const fetchConnectors = experienceAdapter.fetchSocialConnectors;
702
+ if (!socialEnabled || !fetchConnectors) {
643
703
  setConnectors([]);
644
704
  return;
645
705
  }
@@ -651,42 +711,57 @@ function HeadlessLoginPanel({
651
711
  if (!cancelled) setConnectors(filtered);
652
712
  };
653
713
  if (!sieBase) {
654
- apply(
655
- allowlist ? FALLBACK_SOCIAL.filter((c) => allowlist.has(c.target)) : FALLBACK_SOCIAL
656
- );
714
+ if (!cancelled) setConnectors([]);
657
715
  return;
658
716
  }
659
- void fetchSocialConnectors({ apiBase: sieBase, appId: config.clientId }).then((list) => {
660
- if (list.length) {
661
- apply(list);
662
- return;
663
- }
664
- apply(
665
- allowlist ? FALLBACK_SOCIAL.filter((c) => allowlist.has(c.target)) : FALLBACK_SOCIAL
666
- );
717
+ void fetchConnectors.call(experienceAdapter, { apiBase: sieBase, appId: config.clientId }).then((list) => {
718
+ apply(list);
667
719
  }).catch(() => {
668
- apply(
669
- allowlist ? FALLBACK_SOCIAL.filter((c) => allowlist.has(c.target)) : FALLBACK_SOCIAL
670
- );
720
+ if (!cancelled) setConnectors([]);
671
721
  });
672
722
  return () => {
673
723
  cancelled = true;
674
724
  };
675
- }, [config.clientId, config.experienceApiBase, config.issuer, socialEnabled, socialProviders]);
676
- 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) => {
677
734
  if (!configured) throw new Error("IdP not configured");
678
735
  if (mode === "redirect") {
679
- await signInRedirect(config, { returnUrl, directSignIn });
736
+ await signInRedirect(config, { returnUrl, ...experienceRequest });
680
737
  return;
681
738
  }
682
- const { session, returnUrl: next } = await signInPopup(config, { returnUrl, directSignIn });
739
+ const { session, returnUrl: next } = await signInPopup(config, {
740
+ returnUrl,
741
+ ...experienceRequest
742
+ });
683
743
  await onOidcSession?.(session, next);
684
744
  };
685
745
  const runSocial = async (target) => {
686
746
  setError("");
687
747
  setLoading(target);
688
748
  try {
689
- 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();
690
765
  } catch (e) {
691
766
  setError(e instanceof Error ? e.message : String(e));
692
767
  setLoading(null);
@@ -709,7 +784,12 @@ function HeadlessLoginPanel({
709
784
  if (!apiBase) {
710
785
  throw new Error(labels.experienceUnavailable);
711
786
  }
712
- 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({
713
793
  apiBase,
714
794
  identifier: identifier.trim(),
715
795
  password,
@@ -743,7 +823,7 @@ function HeadlessLoginPanel({
743
823
  ] }),
744
824
  /* @__PURE__ */ jsxRuntime.jsx("p", { className: HeadlessLoginPanel_module_default.subtitle, children: labels.subtitle }),
745
825
  configured ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
746
- /* @__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: [
747
827
  /* @__PURE__ */ jsxRuntime.jsx(
748
828
  "input",
749
829
  {
@@ -785,7 +865,16 @@ function HeadlessLoginPanel({
785
865
  )
786
866
  ] }),
787
867
  /* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: HeadlessLoginPanel_module_default.primaryBtn, disabled: busy || !identifier || !password, children: loading === "password" ? "\u2026" : labels.submitPassword })
788
- ] }),
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
+ ) }),
789
878
  showHint ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: HeadlessLoginPanel_module_default.hint, children: labels.hint }) : null,
790
879
  showSocial ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: HeadlessLoginPanel_module_default.divider, "aria-hidden": true, children: [
791
880
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: HeadlessLoginPanel_module_default.dividerLine }),
@@ -1012,10 +1101,14 @@ function createPostLoginPathHelpers(options) {
1012
1101
  exports.AuthGateProvider = AuthGateProvider;
1013
1102
  exports.DEFAULT_LOGIN_THEME_COLOR = DEFAULT_LOGIN_THEME_COLOR;
1014
1103
  exports.HeadlessLoginPanel = HeadlessLoginPanel;
1104
+ exports.LOGIN_EXPERIENCE_CAPABILITIES = LOGIN_EXPERIENCE_CAPABILITIES;
1105
+ exports.LogtoExperienceAdapter = LogtoExperienceAdapter;
1015
1106
  exports.LuminaryAuthProvider = LuminaryAuthProvider;
1016
1107
  exports.ReauthOverlay = ReauthOverlay;
1017
1108
  exports.authGate = authGate;
1018
1109
  exports.clearStoredSession = clearStoredSession;
1110
+ exports.createLoginExperienceAdapter = createLoginExperienceAdapter;
1111
+ exports.createLogtoDirectSignInRequest = createLogtoDirectSignInRequest;
1019
1112
  exports.createPostLoginPathHelpers = createPostLoginPathHelpers;
1020
1113
  exports.createUserManager = createUserManager;
1021
1114
  exports.experiencePasswordSignIn = experiencePasswordSignIn;
@@ -1031,6 +1124,7 @@ exports.readIdpConfigFromEnv = readIdpConfigFromEnv;
1031
1124
  exports.resetUserManager = resetUserManager;
1032
1125
  exports.resolveExperienceApiBase = resolveExperienceApiBase;
1033
1126
  exports.resolveIssuer = resolveIssuer;
1127
+ exports.resolveLoginExperienceAdapter = resolveLoginExperienceAdapter;
1034
1128
  exports.sameOriginAuthorizeUrl = sameOriginAuthorizeUrl;
1035
1129
  exports.signInPopup = signInPopup;
1036
1130
  exports.signInRedirect = signInRedirect;