@jskit-ai/auth-web 0.1.9 → 0.1.10

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.
@@ -0,0 +1,262 @@
1
+ import { computed, ref } from "vue";
2
+ import {
3
+ resolveSurfaceIdFromPlacementPathname,
4
+ resolveSurfaceRootPathFromPlacementContext
5
+ } from "@jskit-ai/shell-web/client/placement";
6
+ import {
7
+ normalizeAuthReturnToPath,
8
+ resolveAllowedReturnToOriginsFromPlacementContext
9
+ } from "../../lib/returnToPath.js";
10
+ import {
11
+ LOGIN_MODE,
12
+ REGISTER_MODE,
13
+ FORGOT_MODE,
14
+ OTP_MODE,
15
+ EMAIL_CONFIRMATION_MODE,
16
+ AUTH_TITLE_BY_MODE,
17
+ AUTH_SUBTITLE_BY_MODE,
18
+ SUBMIT_LABEL_BY_MODE
19
+ } from "./constants.js";
20
+ import { normalizeEmailAddress, maskEmail } from "./identityHelpers.js";
21
+ import {
22
+ createRememberedAccountHint,
23
+ writeRememberedAccountHint,
24
+ clearRememberedAccountHint
25
+ } from "./rememberedAccountStorage.js";
26
+
27
+ export function useLoginViewState({ placementContext } = {}) {
28
+ const mode = ref(LOGIN_MODE);
29
+ const email = ref("");
30
+ const password = ref("");
31
+ const confirmPassword = ref("");
32
+ const otpCode = ref("");
33
+ const showPassword = ref(false);
34
+ const showConfirmPassword = ref(false);
35
+ const emailTouched = ref(false);
36
+ const passwordTouched = ref(false);
37
+ const confirmPasswordTouched = ref(false);
38
+ const otpCodeTouched = ref(false);
39
+ const submitAttempted = ref(false);
40
+ const rememberAccountOnDevice = ref(true);
41
+ const rememberedAccount = ref(null);
42
+ const useRememberedAccount = ref(false);
43
+ const oauthProviders = ref([]);
44
+ const oauthDefaultProvider = ref("");
45
+ const loading = ref(false);
46
+ const otpRequestPending = ref(false);
47
+ const registerConfirmationResendPending = ref(false);
48
+ const errorMessage = ref("");
49
+ const infoMessage = ref("");
50
+ const pendingEmailConfirmationMessage = ref("");
51
+ const pendingEmailConfirmationAddress = ref("");
52
+
53
+ const isLogin = computed(() => mode.value === LOGIN_MODE);
54
+ const isRegister = computed(() => mode.value === REGISTER_MODE);
55
+ const isForgot = computed(() => mode.value === FORGOT_MODE);
56
+ const isOtp = computed(() => mode.value === OTP_MODE);
57
+ const isEmailConfirmationPending = computed(() => mode.value === EMAIL_CONFIRMATION_MODE);
58
+ const showRememberedAccount = computed(
59
+ () => (isLogin.value || isOtp.value) && useRememberedAccount.value && Boolean(rememberedAccount.value)
60
+ );
61
+ const rememberedAccountDisplayName = computed(() => String(rememberedAccount.value?.displayName || "your account"));
62
+ const rememberedAccountMaskedEmail = computed(() => String(rememberedAccount.value?.maskedEmail || ""));
63
+ const rememberedAccountSwitchLabel = "Use another account";
64
+ const authTitle = computed(() => AUTH_TITLE_BY_MODE[mode.value] || AUTH_TITLE_BY_MODE[LOGIN_MODE]);
65
+ const authSubtitle = computed(() => {
66
+ if (isEmailConfirmationPending.value) {
67
+ const maskedEmail = maskEmail(pendingEmailConfirmationAddress.value);
68
+ if (maskedEmail) {
69
+ return `Open the confirmation link sent to ${maskedEmail} to finish signing in.`;
70
+ }
71
+ return "Open the confirmation link from your inbox to finish signing in.";
72
+ }
73
+ return AUTH_SUBTITLE_BY_MODE[mode.value] || AUTH_SUBTITLE_BY_MODE[LOGIN_MODE];
74
+ });
75
+ const submitLabel = computed(() => SUBMIT_LABEL_BY_MODE[mode.value] || SUBMIT_LABEL_BY_MODE[LOGIN_MODE]);
76
+ const allowedReturnToOrigins = computed(() =>
77
+ resolveAllowedReturnToOriginsFromPlacementContext(placementContext?.value)
78
+ );
79
+ const requestedReturnTo = ref(
80
+ normalizeAuthReturnToPath(
81
+ typeof window === "object" ? new URLSearchParams(window.location.search || "").get("returnTo") : "/",
82
+ "/",
83
+ {
84
+ allowedOrigins: allowedReturnToOrigins.value
85
+ }
86
+ )
87
+ );
88
+ const mainScreenPath = computed(() => {
89
+ const normalizedReturnTo = normalizeAuthReturnToPath(requestedReturnTo.value, "/", {
90
+ allowedOrigins: allowedReturnToOrigins.value
91
+ });
92
+ const surfaceId = resolveSurfaceIdFromPlacementPathname(placementContext?.value, normalizedReturnTo);
93
+ const rootPath = resolveSurfaceRootPathFromPlacementContext(placementContext?.value, surfaceId || "");
94
+ return normalizeAuthReturnToPath(rootPath, "/", {
95
+ allowedOrigins: allowedReturnToOrigins.value
96
+ });
97
+ });
98
+ const emailConfirmationMessage = computed(
99
+ () =>
100
+ String(pendingEmailConfirmationMessage.value || "").trim() ||
101
+ "Please confirm your email address. After confirmation, you can sign in."
102
+ );
103
+
104
+ function clearTransientMessages() {
105
+ errorMessage.value = "";
106
+ infoMessage.value = "";
107
+ }
108
+
109
+ function resetTransientValidationState() {
110
+ submitAttempted.value = false;
111
+ emailTouched.value = false;
112
+ passwordTouched.value = false;
113
+ confirmPasswordTouched.value = false;
114
+ otpCodeTouched.value = false;
115
+ }
116
+
117
+ function clearRememberedAccountState() {
118
+ rememberedAccount.value = null;
119
+ useRememberedAccount.value = false;
120
+ }
121
+
122
+ function resetCredentialFields() {
123
+ password.value = "";
124
+ confirmPassword.value = "";
125
+ otpCode.value = "";
126
+ showPassword.value = false;
127
+ showConfirmPassword.value = false;
128
+ }
129
+
130
+ function resolveNormalizedEmail() {
131
+ return normalizeEmailAddress(email.value);
132
+ }
133
+
134
+ function applyRememberedAccountHint(hint) {
135
+ if (!hint) {
136
+ clearRememberedAccountState();
137
+ return;
138
+ }
139
+
140
+ rememberedAccount.value = hint;
141
+ useRememberedAccount.value = true;
142
+ rememberAccountOnDevice.value = true;
143
+ email.value = String(hint.email || "").trim();
144
+ }
145
+
146
+ function applyRememberedAccountPreference({ email: accountEmail, displayName, shouldRemember } = {}) {
147
+ const rememberedHint = createRememberedAccountHint({
148
+ email: accountEmail,
149
+ displayName,
150
+ lastUsedAt: new Date().toISOString()
151
+ });
152
+
153
+ if (shouldRemember && rememberedHint) {
154
+ writeRememberedAccountHint(rememberedHint);
155
+ applyRememberedAccountHint(rememberedHint);
156
+ return;
157
+ }
158
+
159
+ clearRememberedAccountHint();
160
+ clearRememberedAccountState();
161
+ }
162
+
163
+ function switchAccount() {
164
+ clearRememberedAccountHint();
165
+ clearRememberedAccountState();
166
+ rememberAccountOnDevice.value = false;
167
+ mode.value = LOGIN_MODE;
168
+ email.value = "";
169
+ resetCredentialFields();
170
+ clearTransientMessages();
171
+ resetTransientValidationState();
172
+ }
173
+
174
+ function switchMode(nextMode) {
175
+ if (nextMode === mode.value) {
176
+ return;
177
+ }
178
+
179
+ mode.value = nextMode;
180
+ resetCredentialFields();
181
+ registerConfirmationResendPending.value = false;
182
+ if (nextMode !== EMAIL_CONFIRMATION_MODE) {
183
+ pendingEmailConfirmationAddress.value = "";
184
+ pendingEmailConfirmationMessage.value = "";
185
+ }
186
+ clearTransientMessages();
187
+ resetTransientValidationState();
188
+
189
+ if (nextMode !== LOGIN_MODE && nextMode !== OTP_MODE) {
190
+ useRememberedAccount.value = false;
191
+ return;
192
+ }
193
+
194
+ if (rememberedAccount.value) {
195
+ useRememberedAccount.value = true;
196
+ }
197
+ }
198
+
199
+ function enterEmailConfirmationPendingState({ emailAddress = "", message = "" } = {}) {
200
+ switchMode(EMAIL_CONFIRMATION_MODE);
201
+ pendingEmailConfirmationAddress.value = normalizeEmailAddress(emailAddress);
202
+ pendingEmailConfirmationMessage.value = String(message || "").trim();
203
+ }
204
+
205
+ function goToMainScreen() {
206
+ if (typeof window !== "object" || !window.location || typeof window.location.assign !== "function") {
207
+ return;
208
+ }
209
+ window.location.assign(mainScreenPath.value);
210
+ }
211
+
212
+ return {
213
+ mode,
214
+ email,
215
+ password,
216
+ confirmPassword,
217
+ otpCode,
218
+ showPassword,
219
+ showConfirmPassword,
220
+ emailTouched,
221
+ passwordTouched,
222
+ confirmPasswordTouched,
223
+ otpCodeTouched,
224
+ submitAttempted,
225
+ rememberAccountOnDevice,
226
+ rememberedAccount,
227
+ useRememberedAccount,
228
+ oauthProviders,
229
+ oauthDefaultProvider,
230
+ loading,
231
+ otpRequestPending,
232
+ registerConfirmationResendPending,
233
+ errorMessage,
234
+ infoMessage,
235
+ pendingEmailConfirmationMessage,
236
+ pendingEmailConfirmationAddress,
237
+ isLogin,
238
+ isRegister,
239
+ isForgot,
240
+ isOtp,
241
+ isEmailConfirmationPending,
242
+ showRememberedAccount,
243
+ rememberedAccountDisplayName,
244
+ rememberedAccountMaskedEmail,
245
+ rememberedAccountSwitchLabel,
246
+ authTitle,
247
+ authSubtitle,
248
+ submitLabel,
249
+ allowedReturnToOrigins,
250
+ requestedReturnTo,
251
+ mainScreenPath,
252
+ emailConfirmationMessage,
253
+ resolveNormalizedEmail,
254
+ applyRememberedAccountHint,
255
+ applyRememberedAccountPreference,
256
+ clearTransientMessages,
257
+ switchMode,
258
+ switchAccount,
259
+ enterEmailConfirmationPendingState,
260
+ goToMainScreen
261
+ };
262
+ }
@@ -0,0 +1,124 @@
1
+ import { computed } from "vue";
2
+ import { authRegisterCommand } from "@jskit-ai/auth-core/shared/commands/authRegisterCommand";
3
+ import { authLoginPasswordCommand } from "@jskit-ai/auth-core/shared/commands/authLoginPasswordCommand";
4
+ import { authLoginOtpRequestCommand } from "@jskit-ai/auth-core/shared/commands/authLoginOtpRequestCommand";
5
+ import { authLoginOtpVerifyCommand } from "@jskit-ai/auth-core/shared/commands/authLoginOtpVerifyCommand";
6
+ import { authPasswordResetRequestCommand } from "@jskit-ai/auth-core/shared/commands/authPasswordResetRequestCommand";
7
+ import {
8
+ validateCommandSection,
9
+ resolveFieldValidationMessage
10
+ } from "./validationHelpers.js";
11
+
12
+ export function useLoginViewValidation({ state } = {}) {
13
+ function resolveFieldErrorMessages({
14
+ shouldValidate,
15
+ commandResource,
16
+ section = "bodyValidator",
17
+ payload,
18
+ fieldName
19
+ } = {}) {
20
+ if (!shouldValidate) {
21
+ return [];
22
+ }
23
+
24
+ const parsed = validateCommandSection(commandResource, section, payload);
25
+ const message = resolveFieldValidationMessage(parsed, fieldName);
26
+ return message ? [message] : [];
27
+ }
28
+
29
+ const emailErrorMessages = computed(() => {
30
+ const shouldValidate = state.submitAttempted.value || state.emailTouched.value;
31
+ const normalizedEmail = state.resolveNormalizedEmail();
32
+ const command = state.isRegister.value
33
+ ? authRegisterCommand
34
+ : state.isForgot.value
35
+ ? authPasswordResetRequestCommand
36
+ : state.isOtp.value
37
+ ? authLoginOtpRequestCommand
38
+ : authLoginPasswordCommand;
39
+ const payload = state.isRegister.value || state.isLogin.value
40
+ ? {
41
+ email: normalizedEmail,
42
+ password: String(state.password.value || "")
43
+ }
44
+ : {
45
+ email: normalizedEmail
46
+ };
47
+
48
+ return resolveFieldErrorMessages({
49
+ shouldValidate,
50
+ commandResource: command,
51
+ payload,
52
+ fieldName: "email"
53
+ });
54
+ });
55
+
56
+ const passwordErrorMessages = computed(() => {
57
+ const shouldValidate = state.submitAttempted.value || state.passwordTouched.value;
58
+ if (!shouldValidate || state.isForgot.value || state.isOtp.value) {
59
+ return [];
60
+ }
61
+
62
+ const normalizedEmail = state.resolveNormalizedEmail();
63
+ const command = state.isRegister.value ? authRegisterCommand : authLoginPasswordCommand;
64
+ return resolveFieldErrorMessages({
65
+ shouldValidate: true,
66
+ commandResource: command,
67
+ payload: {
68
+ email: normalizedEmail,
69
+ password: String(state.password.value || "")
70
+ },
71
+ fieldName: "password"
72
+ });
73
+ });
74
+
75
+ const confirmPasswordErrorMessages = computed(() => {
76
+ const shouldValidate = state.submitAttempted.value || state.confirmPasswordTouched.value;
77
+ if (!shouldValidate || !state.isRegister.value) {
78
+ return [];
79
+ }
80
+ if (String(state.confirmPassword.value || "").trim() !== String(state.password.value || "").trim()) {
81
+ return ["Passwords do not match."];
82
+ }
83
+ return [];
84
+ });
85
+
86
+ const otpCodeErrorMessages = computed(() => {
87
+ const shouldValidate = state.submitAttempted.value || state.otpCodeTouched.value;
88
+ return resolveFieldErrorMessages({
89
+ shouldValidate: shouldValidate && state.isOtp.value,
90
+ commandResource: authLoginOtpVerifyCommand,
91
+ payload: {
92
+ token: String(state.otpCode.value || "").trim()
93
+ },
94
+ fieldName: "token"
95
+ });
96
+ });
97
+
98
+ const canSubmit = computed(() => {
99
+ if (state.isEmailConfirmationPending.value) {
100
+ return false;
101
+ }
102
+ if (state.loading.value) {
103
+ return false;
104
+ }
105
+ if (emailErrorMessages.value.length > 0) {
106
+ return false;
107
+ }
108
+ if (state.isRegister.value || state.isLogin.value) {
109
+ return passwordErrorMessages.value.length < 1 && confirmPasswordErrorMessages.value.length < 1;
110
+ }
111
+ if (state.isOtp.value) {
112
+ return otpCodeErrorMessages.value.length < 1;
113
+ }
114
+ return true;
115
+ });
116
+
117
+ return {
118
+ emailErrorMessages,
119
+ passwordErrorMessages,
120
+ confirmPasswordErrorMessages,
121
+ otpCodeErrorMessages,
122
+ canSubmit
123
+ };
124
+ }
@@ -0,0 +1,65 @@
1
+ import { validateOperationSection } from "@jskit-ai/http-runtime/shared/validators/operationValidation";
2
+
3
+ function validateCommandSection(commandResource, section, payload) {
4
+ if (!commandResource || !commandResource.operation) {
5
+ return {
6
+ ok: true,
7
+ fieldErrors: {},
8
+ globalErrors: []
9
+ };
10
+ }
11
+
12
+ return validateOperationSection({
13
+ operation: commandResource.operation,
14
+ section,
15
+ value: payload
16
+ });
17
+ }
18
+
19
+ function resolveValidationMessage(validationResult, fallbackMessage = "Validation failed.") {
20
+ if (!validationResult || validationResult.ok) {
21
+ return "";
22
+ }
23
+
24
+ const fieldErrors = validationResult.fieldErrors && typeof validationResult.fieldErrors === "object"
25
+ ? validationResult.fieldErrors
26
+ : {};
27
+ const firstFieldError = Object.values(fieldErrors).find((entry) => String(entry || "").trim().length > 0);
28
+ if (firstFieldError) {
29
+ return String(firstFieldError);
30
+ }
31
+
32
+ const globalErrors = Array.isArray(validationResult.globalErrors) ? validationResult.globalErrors : [];
33
+ const firstGlobalError = globalErrors.find((entry) => String(entry || "").trim().length > 0);
34
+ if (firstGlobalError) {
35
+ return String(firstGlobalError);
36
+ }
37
+
38
+ return String(fallbackMessage || "Validation failed.");
39
+ }
40
+
41
+ function resolveFieldValidationMessage(validationResult, fieldName = "") {
42
+ if (!validationResult || validationResult.ok) {
43
+ return "";
44
+ }
45
+
46
+ const fieldErrors = validationResult.fieldErrors && typeof validationResult.fieldErrors === "object"
47
+ ? validationResult.fieldErrors
48
+ : {};
49
+ return String(fieldErrors[fieldName] || "").trim();
50
+ }
51
+
52
+ function ensureCommandSectionValid(commandResource, section, payload, fallbackMessage) {
53
+ const validation = validateCommandSection(commandResource, section, payload);
54
+ if (validation.ok) {
55
+ return;
56
+ }
57
+ throw new Error(resolveValidationMessage(validation, fallbackMessage));
58
+ }
59
+
60
+ export {
61
+ validateCommandSection,
62
+ resolveValidationMessage,
63
+ resolveFieldValidationMessage,
64
+ ensureCommandSectionValid
65
+ };
@@ -1,6 +1,8 @@
1
1
  import { isTransientQueryError } from "@jskit-ai/kernel/shared/support";
2
2
  import { AUTH_PATHS } from "@jskit-ai/auth-core/shared/authPaths";
3
3
  import { isExternalLinkTarget } from "@jskit-ai/kernel/shared/support/linkPath";
4
+ import { normalizePathname as normalizeSurfacePathname } from "@jskit-ai/kernel/shared/surface/paths";
5
+ import { createListenerSubscription } from "@jskit-ai/kernel/shared/support/listenerSet";
4
6
 
5
7
  const GLOBAL_GUARD_EVALUATOR_KEY = "__JSKIT_WEB_SHELL_GUARD_EVALUATOR__";
6
8
  const AUTH_POLICY_AUTHENTICATED = "authenticated";
@@ -9,6 +11,25 @@ const DEFAULT_LOGIN_ROUTE = "/auth/login";
9
11
  const DEFAULT_REFRESH_ON_FOREGROUND = false;
10
12
  const DEFAULT_REFRESH_ON_RECONNECT = false;
11
13
  const DEFAULT_REALTIME_REFRESH_EVENTS = Object.freeze(["users.bootstrap.changed", "auth.session.changed"]);
14
+ const OAUTH_QUERY_PARAM_RETURN_TO = "returnTo";
15
+ const OAUTH_CALLBACK_PARAM_KEYS = Object.freeze([
16
+ "code",
17
+ "access_token",
18
+ "refresh_token",
19
+ "provider_token",
20
+ "expires_in",
21
+ "expires_at",
22
+ "token_type",
23
+ "state",
24
+ "sb",
25
+ "type",
26
+ "error",
27
+ "error_code",
28
+ "error_description",
29
+ "errorCode",
30
+ "errorDescription",
31
+ "token_hash"
32
+ ]);
12
33
  const KEEP_PREVIOUS_AUTH_STATE = Symbol("keepPreviousAuthState");
13
34
  const DEFAULT_AUTH_STATE = Object.freeze({
14
35
  authenticated: false,
@@ -26,13 +47,11 @@ function asGlobalObject() {
26
47
 
27
48
  function normalizePathname(pathname, fallback = "/") {
28
49
  const raw = String(pathname || "").trim();
29
- if (!raw || !raw.startsWith("/")) {
50
+ if (!raw || !raw.startsWith("/") || raw.startsWith("//")) {
30
51
  return fallback;
31
52
  }
32
- if (raw.startsWith("//")) {
33
- return fallback;
34
- }
35
- return raw;
53
+
54
+ return normalizeSurfacePathname(raw);
36
55
  }
37
56
 
38
57
  function normalizeLoginRoute(loginRoute, fallback = DEFAULT_LOGIN_ROUTE) {
@@ -247,6 +266,60 @@ function normalizeRuntimePath(value, fallback) {
247
266
  return raw || fallback;
248
267
  }
249
268
 
269
+ function hasOAuthCallbackParams({ search = "", hash = "" } = {}) {
270
+ const searchParams = new URLSearchParams(String(search || ""));
271
+ const hashParams = new URLSearchParams(String(hash || "").replace(/^#/, ""));
272
+ return OAUTH_CALLBACK_PARAM_KEYS.some((key) => searchParams.has(key) || hashParams.has(key));
273
+ }
274
+
275
+ function stripOAuthCallbackParamsFromSearch(search = "") {
276
+ const params = new URLSearchParams(String(search || ""));
277
+ OAUTH_CALLBACK_PARAM_KEYS.forEach((key) => {
278
+ params.delete(key);
279
+ });
280
+ params.delete(OAUTH_QUERY_PARAM_RETURN_TO);
281
+ return params;
282
+ }
283
+
284
+ function redirectOAuthCallbackToLoginRoute(loginRoute) {
285
+ if (
286
+ typeof window !== "object" ||
287
+ !window ||
288
+ !window.location ||
289
+ typeof window.location.replace !== "function"
290
+ ) {
291
+ return false;
292
+ }
293
+
294
+ const normalizedLoginRoute = normalizeLoginRoute(loginRoute, DEFAULT_LOGIN_ROUTE);
295
+ if (isExternalLinkTarget(normalizedLoginRoute)) {
296
+ return false;
297
+ }
298
+
299
+ const currentPathname = normalizePathname(window.location.pathname || "", "/");
300
+ const loginPathname = normalizePathname(normalizedLoginRoute, DEFAULT_LOGIN_ROUTE);
301
+ if (currentPathname === loginPathname) {
302
+ return false;
303
+ }
304
+
305
+ const currentSearch = String(window.location.search || "");
306
+ const currentHash = String(window.location.hash || "");
307
+ if (!hasOAuthCallbackParams({ search: currentSearch, hash: currentHash })) {
308
+ return false;
309
+ }
310
+
311
+ const returnToParams = stripOAuthCallbackParamsFromSearch(currentSearch);
312
+ const returnToQuery = returnToParams.toString();
313
+ const returnTo = `${currentPathname}${returnToQuery ? `?${returnToQuery}` : ""}`;
314
+
315
+ const nextParams = new URLSearchParams(currentSearch);
316
+ nextParams.set(OAUTH_QUERY_PARAM_RETURN_TO, returnTo);
317
+ const nextQuery = nextParams.toString();
318
+ const nextPath = `${loginPathname}${nextQuery ? `?${nextQuery}` : ""}${currentHash}`;
319
+ window.location.replace(nextPath);
320
+ return true;
321
+ }
322
+
250
323
  function asEventTarget(value) {
251
324
  if (!value || typeof value !== "object") {
252
325
  return null;
@@ -335,6 +408,7 @@ function createAuthGuardRuntime({
335
408
  let activeRefreshPromise = null;
336
409
  let listenersInstalled = false;
337
410
  const listeners = new Set();
411
+ const subscribe = createListenerSubscription(listeners);
338
412
 
339
413
  function notifyListeners() {
340
414
  for (const listener of listeners) {
@@ -350,16 +424,6 @@ function createAuthGuardRuntime({
350
424
  return authState;
351
425
  }
352
426
 
353
- function subscribe(listener) {
354
- if (typeof listener !== "function") {
355
- return () => {};
356
- }
357
- listeners.add(listener);
358
- return () => {
359
- listeners.delete(listener);
360
- };
361
- }
362
-
363
427
  async function refresh({ sessionPath: nextSessionPath } = {}) {
364
428
  currentSessionPath = normalizeRuntimePath(nextSessionPath, currentSessionPath);
365
429
  if (activeRefreshPromise) {
@@ -392,6 +456,10 @@ function createAuthGuardRuntime({
392
456
  async function initialize({ sessionPath: nextSessionPath, loginRoute: nextLoginRoute } = {}) {
393
457
  currentSessionPath = normalizeRuntimePath(nextSessionPath, currentSessionPath);
394
458
  currentLoginRoute = normalizeLoginRoute(nextLoginRoute, currentLoginRoute);
459
+ if (redirectOAuthCallbackToLoginRoute(currentLoginRoute)) {
460
+ return authState;
461
+ }
462
+
395
463
  installGuardEvaluator({
396
464
  loginRoute: currentLoginRoute,
397
465
  getAuthState: () => authState
@@ -1,7 +1,73 @@
1
- import { useDefaultLoginView } from "../composables/useDefaultLoginView.js";
1
+ import { onMounted } from "vue";
2
+ import { useQueryClient } from "@tanstack/vue-query";
3
+ import { useShellWebErrorRuntime } from "@jskit-ai/shell-web/client/error";
4
+ import { useWebPlacementContext } from "@jskit-ai/shell-web/client/placement";
5
+ import { useLoginViewState } from "../composables/loginView/useLoginViewState.js";
6
+ import { useLoginViewValidation } from "../composables/loginView/useLoginViewValidation.js";
7
+ import { useLoginViewActions } from "../composables/loginView/useLoginViewActions.js";
2
8
 
3
9
  function useLoginView() {
4
- return useDefaultLoginView();
10
+ const { context: placementContext } = useWebPlacementContext();
11
+ const queryClient = useQueryClient();
12
+ const errorRuntime = useShellWebErrorRuntime();
13
+
14
+ const state = useLoginViewState({ placementContext });
15
+ const validation = useLoginViewValidation({ state });
16
+ const actions = useLoginViewActions({
17
+ state,
18
+ validation,
19
+ queryClient,
20
+ errorRuntime
21
+ });
22
+
23
+ onMounted(actions.initializeOnMounted);
24
+
25
+ return {
26
+ authTitle: state.authTitle,
27
+ authSubtitle: state.authSubtitle,
28
+ isForgot: state.isForgot,
29
+ isOtp: state.isOtp,
30
+ isLogin: state.isLogin,
31
+ isRegister: state.isRegister,
32
+ isEmailConfirmationPending: state.isEmailConfirmationPending,
33
+ emailConfirmationMessage: state.emailConfirmationMessage,
34
+ showRememberedAccount: state.showRememberedAccount,
35
+ switchMode: state.switchMode,
36
+ goToMainScreen: state.goToMainScreen,
37
+ submitAuth: actions.submitAuth,
38
+ rememberedAccountDisplayName: state.rememberedAccountDisplayName,
39
+ rememberedAccountMaskedEmail: state.rememberedAccountMaskedEmail,
40
+ rememberedAccountSwitchLabel: state.rememberedAccountSwitchLabel,
41
+ switchAccount: state.switchAccount,
42
+ email: state.email,
43
+ emailErrorMessages: validation.emailErrorMessages,
44
+ emailTouched: state.emailTouched,
45
+ password: state.password,
46
+ showPassword: state.showPassword,
47
+ passwordErrorMessages: validation.passwordErrorMessages,
48
+ passwordTouched: state.passwordTouched,
49
+ confirmPassword: state.confirmPassword,
50
+ showConfirmPassword: state.showConfirmPassword,
51
+ confirmPasswordErrorMessages: validation.confirmPasswordErrorMessages,
52
+ confirmPasswordTouched: state.confirmPasswordTouched,
53
+ otpCode: state.otpCode,
54
+ otpCodeErrorMessages: validation.otpCodeErrorMessages,
55
+ otpCodeTouched: state.otpCodeTouched,
56
+ rememberAccountOnDevice: state.rememberAccountOnDevice,
57
+ otpRequestPending: state.otpRequestPending,
58
+ registerConfirmationResendPending: state.registerConfirmationResendPending,
59
+ requestOtpCode: actions.requestOtpCode,
60
+ resendRegisterConfirmationEmail: actions.resendRegisterConfirmationEmail,
61
+ oauthProviders: state.oauthProviders,
62
+ loading: state.loading,
63
+ oauthProviderIcon: actions.oauthProviderIcon,
64
+ startOAuthSignIn: actions.startOAuthSignIn,
65
+ oauthProviderButtonLabel: actions.oauthProviderButtonLabel,
66
+ errorMessage: state.errorMessage,
67
+ infoMessage: state.infoMessage,
68
+ canSubmit: validation.canSubmit,
69
+ submitLabel: state.submitLabel
70
+ };
5
71
  }
6
72
 
7
- export { useLoginView, useDefaultLoginView };
73
+ export { useLoginView };