@jskit-ai/auth-web 0.1.8 → 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.
@@ -1,7 +1,7 @@
1
1
  export default Object.freeze({
2
2
  "packageVersion": 1,
3
3
  "packageId": "@jskit-ai/auth-web",
4
- "version": "0.1.8",
4
+ "version": "0.1.10",
5
5
  "description": "Auth web module: Fastify auth routes plus web login/sign-out scaffolds.",
6
6
  "dependsOn": [
7
7
  "@jskit-ai/auth-core",
@@ -219,19 +219,23 @@ export default Object.freeze({
219
219
  "mutations": {
220
220
  "dependencies": {
221
221
  "runtime": {
222
- "@tanstack/vue-query": "^5.90.5",
222
+ "@tanstack/vue-query": "5.92.12",
223
223
  "@mdi/js": "^7.4.47",
224
224
  "@fastify/type-provider-typebox": "^6.1.0",
225
- "@jskit-ai/auth-core": "0.1.8",
226
- "@jskit-ai/http-runtime": "0.1.8",
227
- "@jskit-ai/kernel": "0.1.8",
228
- "@jskit-ai/shell-web": "0.1.8",
225
+ "@jskit-ai/auth-core": "0.1.10",
226
+ "@jskit-ai/http-runtime": "0.1.10",
227
+ "@jskit-ai/kernel": "0.1.10",
228
+ "@jskit-ai/shell-web": "0.1.10",
229
229
  "vuetify": "^4.0.0"
230
230
  },
231
231
  "dev": {}
232
232
  },
233
233
  "packageJson": {
234
- "scripts": {}
234
+ "scripts": {
235
+ "server:auth": "SERVER_SURFACE=auth node ./bin/server.js",
236
+ "dev:auth": "VITE_SURFACE=auth vite",
237
+ "build:auth": "VITE_SURFACE=auth vite build"
238
+ }
235
239
  },
236
240
  "procfile": {},
237
241
  "files": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jskit-ai/auth-web",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "test": "node --test"
@@ -18,12 +18,12 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "@tanstack/vue-query": "^5.90.5",
21
- "@jskit-ai/auth-core": "0.1.8",
21
+ "@jskit-ai/auth-core": "0.1.10",
22
22
  "@mdi/js": "^7.4.47",
23
23
  "@fastify/type-provider-typebox": "^6.1.0",
24
- "@jskit-ai/kernel": "0.1.8",
25
- "@jskit-ai/shell-web": "0.1.8",
24
+ "@jskit-ai/kernel": "0.1.10",
25
+ "@jskit-ai/shell-web": "0.1.10",
26
26
  "vuetify": "^4.0.0",
27
- "@jskit-ai/http-runtime": "0.1.8"
27
+ "@jskit-ai/http-runtime": "0.1.10"
28
28
  }
29
29
  }
@@ -0,0 +1,42 @@
1
+ const LOGIN_MODE = "login";
2
+ const REGISTER_MODE = "register";
3
+ const FORGOT_MODE = "forgot";
4
+ const OTP_MODE = "otp";
5
+ const EMAIL_CONFIRMATION_MODE = "confirm-email";
6
+
7
+ const AUTH_TITLE_BY_MODE = Object.freeze({
8
+ [LOGIN_MODE]: "Welcome back",
9
+ [REGISTER_MODE]: "Create your account",
10
+ [FORGOT_MODE]: "Reset your password",
11
+ [OTP_MODE]: "Use one-time code",
12
+ [EMAIL_CONFIRMATION_MODE]: "Confirm your email"
13
+ });
14
+
15
+ const AUTH_SUBTITLE_BY_MODE = Object.freeze({
16
+ [LOGIN_MODE]: "Sign in to continue.",
17
+ [REGISTER_MODE]: "Register to access your workspace.",
18
+ [FORGOT_MODE]: "We will send password reset instructions to your email.",
19
+ [OTP_MODE]: "Request a one-time login code and verify it below."
20
+ });
21
+
22
+ const SUBMIT_LABEL_BY_MODE = Object.freeze({
23
+ [LOGIN_MODE]: "Sign in",
24
+ [REGISTER_MODE]: "Register",
25
+ [FORGOT_MODE]: "Send reset instructions",
26
+ [OTP_MODE]: "Verify code",
27
+ [EMAIL_CONFIRMATION_MODE]: "Continue"
28
+ });
29
+
30
+ const DEFAULT_REGISTER_CONFIRMATION_MESSAGE = "Check your email to confirm the account before logging in.";
31
+
32
+ export {
33
+ LOGIN_MODE,
34
+ REGISTER_MODE,
35
+ FORGOT_MODE,
36
+ OTP_MODE,
37
+ EMAIL_CONFIRMATION_MODE,
38
+ AUTH_TITLE_BY_MODE,
39
+ AUTH_SUBTITLE_BY_MODE,
40
+ SUBMIT_LABEL_BY_MODE,
41
+ DEFAULT_REGISTER_CONFIRMATION_MESSAGE
42
+ };
@@ -0,0 +1,23 @@
1
+ function normalizeEmailAddress(value) {
2
+ return String(value || "")
3
+ .trim()
4
+ .toLowerCase();
5
+ }
6
+
7
+ function maskEmail(emailAddress) {
8
+ const normalized = normalizeEmailAddress(emailAddress);
9
+ const separatorIndex = normalized.indexOf("@");
10
+ if (separatorIndex <= 0) {
11
+ return normalized;
12
+ }
13
+
14
+ const localPart = normalized.slice(0, separatorIndex);
15
+ const domainPart = normalized.slice(separatorIndex + 1);
16
+ const visiblePrefix = localPart.slice(0, 1);
17
+ return `${visiblePrefix}***@${domainPart}`;
18
+ }
19
+
20
+ export {
21
+ normalizeEmailAddress,
22
+ maskEmail
23
+ };
@@ -0,0 +1,90 @@
1
+ import {
2
+ OAUTH_QUERY_PARAM_PROVIDER,
3
+ OAUTH_QUERY_PARAM_RETURN_TO
4
+ } from "@jskit-ai/auth-core/shared/oauthCallbackParams";
5
+
6
+ function stripOAuthParamsFromLocation() {
7
+ if (typeof window !== "object" || !window.location) {
8
+ return;
9
+ }
10
+
11
+ const nextUrl = new URL(window.location.href);
12
+ const oauthParamKeys = [
13
+ "code",
14
+ "access_token",
15
+ "refresh_token",
16
+ "provider_token",
17
+ "expires_in",
18
+ "expires_at",
19
+ "token_type",
20
+ "state",
21
+ "sb",
22
+ "type",
23
+ "error",
24
+ "error_description",
25
+ "errorCode",
26
+ "errorDescription",
27
+ OAUTH_QUERY_PARAM_PROVIDER,
28
+ OAUTH_QUERY_PARAM_RETURN_TO
29
+ ];
30
+
31
+ oauthParamKeys.forEach((key) => {
32
+ nextUrl.searchParams.delete(key);
33
+ });
34
+
35
+ const hashParams = new URLSearchParams((nextUrl.hash || "").replace(/^#/, ""));
36
+ oauthParamKeys.forEach((key) => {
37
+ hashParams.delete(key);
38
+ });
39
+
40
+ const nextHash = hashParams.toString();
41
+ window.history.replaceState({}, "", `${nextUrl.pathname}${nextUrl.search}${nextHash ? `#${nextHash}` : ""}`);
42
+ }
43
+
44
+ function readOAuthCallbackParamsFromLocation() {
45
+ if (typeof window !== "object" || !window.location) {
46
+ return null;
47
+ }
48
+
49
+ const searchParams = new URLSearchParams(window.location.search || "");
50
+ const hashParams = new URLSearchParams((window.location.hash || "").replace(/^#/, ""));
51
+
52
+ const code = String(searchParams.get("code") || hashParams.get("code") || "").trim();
53
+ const accessToken = String(searchParams.get("access_token") || hashParams.get("access_token") || "").trim();
54
+ const refreshToken = String(searchParams.get("refresh_token") || hashParams.get("refresh_token") || "").trim();
55
+ const errorCode = String(
56
+ searchParams.get("error") ||
57
+ hashParams.get("error") ||
58
+ searchParams.get("errorCode") ||
59
+ hashParams.get("errorCode") ||
60
+ ""
61
+ ).trim();
62
+ const errorDescription = String(
63
+ searchParams.get("error_description") ||
64
+ hashParams.get("error_description") ||
65
+ searchParams.get("errorDescription") ||
66
+ hashParams.get("errorDescription") ||
67
+ ""
68
+ ).trim();
69
+ const hasSessionPair = Boolean(accessToken && refreshToken);
70
+
71
+ if (!code && !hasSessionPair && !errorCode) {
72
+ return null;
73
+ }
74
+
75
+ return {
76
+ code,
77
+ accessToken,
78
+ refreshToken,
79
+ hasSessionPair,
80
+ errorCode,
81
+ errorDescription,
82
+ provider: String(searchParams.get(OAUTH_QUERY_PARAM_PROVIDER) || "").trim().toLowerCase(),
83
+ returnTo: String(searchParams.get(OAUTH_QUERY_PARAM_RETURN_TO) || "").trim()
84
+ };
85
+ }
86
+
87
+ export {
88
+ stripOAuthParamsFromLocation,
89
+ readOAuthCallbackParamsFromLocation
90
+ };
@@ -0,0 +1,18 @@
1
+ import { DEFAULT_REGISTER_CONFIRMATION_MESSAGE } from "./constants.js";
2
+
3
+ function resolveRegisterCompletionState(registerResult) {
4
+ if (registerResult?.requiresEmailConfirmation === true) {
5
+ const message = String(registerResult?.message || "").trim() || DEFAULT_REGISTER_CONFIRMATION_MESSAGE;
6
+ return {
7
+ shouldCompleteLogin: false,
8
+ message
9
+ };
10
+ }
11
+
12
+ return {
13
+ shouldCompleteLogin: true,
14
+ message: ""
15
+ };
16
+ }
17
+
18
+ export { resolveRegisterCompletionState };
@@ -0,0 +1,95 @@
1
+ import { normalizeEmailAddress, maskEmail } from "./identityHelpers.js";
2
+
3
+ const REMEMBERED_ACCOUNT_STORAGE_KEY = "auth.rememberedAccount";
4
+
5
+ function resolveLocalStorage() {
6
+ if (typeof window === "undefined" || !window.localStorage) {
7
+ return null;
8
+ }
9
+
10
+ try {
11
+ const probeKey = "__auth_hint_probe__";
12
+ window.localStorage.setItem(probeKey, "1");
13
+ window.localStorage.removeItem(probeKey);
14
+ return window.localStorage;
15
+ } catch {
16
+ return null;
17
+ }
18
+ }
19
+
20
+ function createRememberedAccountHint({ email: accountEmail, displayName, maskedEmail, lastUsedAt } = {}) {
21
+ const normalizedEmail = normalizeEmailAddress(accountEmail);
22
+ if (!normalizedEmail) {
23
+ return null;
24
+ }
25
+
26
+ const normalizedDisplayName = String(displayName || "").trim() || normalizedEmail.split("@")[0] || "User";
27
+ const normalizedMaskedEmail =
28
+ normalizedEmail.includes("@") && !maskedEmail ? maskEmail(normalizedEmail) : String(maskedEmail || "").trim();
29
+
30
+ return {
31
+ email: normalizedEmail,
32
+ displayName: normalizedDisplayName,
33
+ maskedEmail: normalizedMaskedEmail,
34
+ lastUsedAt: String(lastUsedAt || new Date().toISOString())
35
+ };
36
+ }
37
+
38
+ function readRememberedAccountHint() {
39
+ const storage = resolveLocalStorage();
40
+ if (!storage) {
41
+ return null;
42
+ }
43
+
44
+ try {
45
+ const rawValue = storage.getItem(REMEMBERED_ACCOUNT_STORAGE_KEY);
46
+ if (!rawValue) {
47
+ return null;
48
+ }
49
+ const parsed = JSON.parse(rawValue);
50
+ return createRememberedAccountHint(parsed);
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+
56
+ function writeRememberedAccountHint(hint) {
57
+ const storage = resolveLocalStorage();
58
+ if (!storage || !hint) {
59
+ return;
60
+ }
61
+
62
+ try {
63
+ storage.setItem(
64
+ REMEMBERED_ACCOUNT_STORAGE_KEY,
65
+ JSON.stringify({
66
+ email: hint.email,
67
+ displayName: hint.displayName,
68
+ maskedEmail: hint.maskedEmail,
69
+ lastUsedAt: hint.lastUsedAt
70
+ })
71
+ );
72
+ } catch {
73
+ // best effort only
74
+ }
75
+ }
76
+
77
+ function clearRememberedAccountHint() {
78
+ const storage = resolveLocalStorage();
79
+ if (!storage) {
80
+ return;
81
+ }
82
+
83
+ try {
84
+ storage.removeItem(REMEMBERED_ACCOUNT_STORAGE_KEY);
85
+ } catch {
86
+ // best effort only
87
+ }
88
+ }
89
+
90
+ export {
91
+ createRememberedAccountHint,
92
+ readRememberedAccountHint,
93
+ writeRememberedAccountHint,
94
+ clearRememberedAccountHint
95
+ };