nexus-shared 1.1.19 → 1.1.21

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.
Files changed (53) hide show
  1. package/package.json +1 -1
  2. package/src/api-services/authentication-service.tsx +23 -0
  3. package/src/api-services/system-service.tsx +24 -316
  4. package/src/client.ts +1 -2
  5. package/src/components/documents/button.tsx +9 -16
  6. package/src/components/documents/icon-box.tsx +1 -1
  7. package/src/components/documents/tab-button.tsx +2 -2
  8. package/src/components/documents/tag.tsx +30 -0
  9. package/src/components/inputs/input-element.tsx +1 -1
  10. package/src/components/inputs/input-form.tsx +2 -2
  11. package/src/components/layouts/global-dialogbox.tsx +5 -9
  12. package/src/components/layouts/global-layout.tsx +8 -0
  13. package/src/components/layouts/layout-helpers.tsx +1 -4
  14. package/src/components/layouts/panels/user-panel.tsx +112 -0
  15. package/src/components/layouts/utility-menu.tsx +9 -29
  16. package/src/components/panels/theme-panel.tsx +2 -2
  17. package/src/helpers/browser-helpers.tsx +48 -3
  18. package/src/helpers/element-helpers.tsx +66 -0
  19. package/src/interface.ts +1 -0
  20. package/src/interfaces/auth-token-interfaces.tsx +6 -0
  21. package/src/interfaces/browser-interfaces.tsx +13 -0
  22. package/src/interfaces/http-interfaces.tsx +0 -3
  23. package/src/interfaces/icon-interfaces.tsx +3 -0
  24. package/src/interfaces/menu-interfaces.tsx +18 -1
  25. package/src/interfaces/storage-interfaces.tsx +1 -0
  26. package/src/interfaces/theme-interfaces.tsx +43 -129
  27. package/src/interfaces/user-interfaces.tsx +30 -0
  28. package/src/nexus.environments.tsx +39 -27
  29. package/src/services/http-services.tsx +6 -6
  30. package/src/services/loader-service.tsx +33 -17
  31. package/src/services/localstorage-service.tsx +23 -6
  32. package/src/services/message-services.tsx +1 -1
  33. package/src/services/theme-service.tsx +32 -16
  34. package/src/services/user-services.tsx +10 -0
  35. package/src/sso-config/auth-token-validation.ts +4 -8
  36. package/src/sso-config/callback-route.tsx +3 -2
  37. package/src/sso-config/cookie-helpers.tsx +47 -22
  38. package/src/sso-config/oauth-callback-state.ts +5 -2
  39. package/src/sso-config/pkce-helpers.ts +2 -9
  40. package/src/sso-config/provider-complete-route.tsx +7 -4
  41. package/src/sso-config/redirect-context-actions.tsx +2 -3
  42. package/src/sso-config/redirect-context-helpers.tsx +20 -5
  43. package/src/sso-config/refresh-route.tsx +5 -4
  44. package/src/sso-config/sign-in-route.tsx +9 -4
  45. package/src/sso-config/sign-out-route.tsx +7 -3
  46. package/src/sso-config/sign-up-route.tsx +14 -3
  47. package/src/sso-config/sso-backend-flow.ts +10 -17
  48. package/src/sso-config/sso-complete-route.tsx +7 -3
  49. package/src/sso-config/sso-config.ts +7 -5
  50. package/src/sso-config/sso-interfaces.tsx +34 -3
  51. package/src/styles/nexus.grid-view.css +42 -0
  52. package/src/styles/nexus.icon.css +1 -0
  53. package/src/styles/nexus.logic.css +34 -5
@@ -1,6 +1,7 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
- import { SetSsoSessionCookie } from "./cookie-helpers";
3
- import { SSO_CONFIG } from "./sso-config";
2
+ import { AUTH_COOKIES, ResolvePostLoginRedirectUrl, SetSsoSessionCookie } from "./cookie-helpers";
3
+ import { DecodeRedirectContext } from "./redirect-context-helpers";
4
+ import { GetClientConfiguration } from "./sso-backend-flow";
4
5
 
5
6
  /** GET — complete provider OAuth by persisting the backend SSO session cookie. */
6
7
  export async function ProviderCompleteRoute(req: NextRequest) {
@@ -8,8 +9,10 @@ export async function ProviderCompleteRoute(req: NextRequest) {
8
9
  const ssoSession = req.nextUrl.searchParams.get("ssoSession");
9
10
 
10
11
  if (!ssoSession) return NextResponse.redirect(signInUrl);
12
+ const ssoConfiguration = await GetClientConfiguration();
11
13
 
12
- const response = NextResponse.redirect(new URL(SSO_CONFIG.FRONTEND_ENDPOINTS.SSO_COMPLETE, req.url));
13
- SetSsoSessionCookie(response, ssoSession, SSO_CONFIG.BACKEND_CONFIG.SSO_SESSION_MAX_AGE);
14
+ const redirectContext = DecodeRedirectContext(req.cookies.get(AUTH_COOKIES.redirectContext)?.value);
15
+ const response = NextResponse.redirect(new URL(ResolvePostLoginRedirectUrl(!!redirectContext?.redirectUri), req.url));
16
+ SetSsoSessionCookie(response, ssoSession, ssoConfiguration.ssoSessionLifetime);
14
17
  return response;
15
18
  }
@@ -3,7 +3,7 @@
3
3
  import { cookies } from "next/headers";
4
4
  import { AUTH_COOKIES } from "./cookie-helpers";
5
5
  import { CreatePkcePair } from "./pkce-helpers";
6
- import { CreateOAuthNonce, DecodeRedirectContext, EncodeRedirectContext, GetRedirectContextCookieOptions, IsAllowedRedirectUri, SanitizeReturnPath } from "./redirect-context-helpers";
6
+ import { ClearRedirectContextStore, CreateOAuthNonce, DecodeRedirectContext, EncodeRedirectContext, GetRedirectContextCookieOptions, IsAllowedRedirectUri, SanitizeReturnPath } from "./redirect-context-helpers";
7
7
  import { IRedirectContext } from "./sso-interfaces";
8
8
 
9
9
  function ReadRedirectContextFromStore(cookieStore: Awaited<ReturnType<typeof cookies>>): IRedirectContext | null {
@@ -41,6 +41,5 @@ export async function PersistRedirectContext(redirectUri?: string | null, state?
41
41
 
42
42
  /** Server Action — clears the redirect context cookie after SSO completes. */
43
43
  export async function ClearRedirectContext() {
44
- const cookieStore = await cookies();
45
- cookieStore.delete(AUTH_COOKIES.redirectContext);
44
+ await ClearRedirectContextStore();
46
45
  }
@@ -1,12 +1,14 @@
1
1
  import { createHmac, randomBytes, timingSafeEqual } from "crypto";
2
2
  import { cookies } from "next/headers";
3
3
  import { NextResponse } from "next/server";
4
- import { URLS } from "../nexus.environments";
4
+ import { NEXUS_INFO, URLS } from "../nexus.environments";
5
5
  import { AUTH_COOKIES } from "./cookie-helpers";
6
- import { CreatePkcePair, PKCE_METHOD_S256 } from "./pkce-helpers";
6
+ import { CreatePkcePair } from "./pkce-helpers";
7
7
  import { SSO_CONFIG } from "./sso-config";
8
- import { IRedirectContext } from "./sso-interfaces";
8
+ import { IRedirectContext, PKCE_METHOD_S256 } from "./sso-interfaces";
9
9
 
10
+ // @ts-ignore
11
+ const processEnv = process.env;
10
12
  const CALLBACK_SUFFIX = "/api/auth/callback";
11
13
 
12
14
  type EncodedRedirectContext = {
@@ -126,7 +128,7 @@ export function GetAuthCookieOptions(maxAge: number | string) {
126
128
  path: "/",
127
129
  sameSite: "lax" as const,
128
130
  maxAge: Number(maxAge),
129
- secure: process.env.NODE_ENV === "production",
131
+ secure: NEXUS_INFO.IS_PRODUCTION,
130
132
  };
131
133
  }
132
134
 
@@ -139,6 +141,19 @@ export function SetRedirectContextCookie(response: NextResponse, context: IRedir
139
141
  response.cookies.set(AUTH_COOKIES.redirectContext, EncodeRedirectContext(context), GetRedirectContextCookieOptions());
140
142
  }
141
143
 
144
+ const redirectContextClearOptions = () => ({
145
+ ...GetRedirectContextCookieOptions(),
146
+ maxAge: 0,
147
+ expires: new Date(0),
148
+ });
149
+
150
+ /** Route Handler / middleware — clears redirect context on the outgoing response. */
142
151
  export function ClearRedirectContextCookie(response: NextResponse) {
143
- response.cookies.set(AUTH_COOKIES.redirectContext, "", { ...GetRedirectContextCookieOptions(), maxAge: 0 });
152
+ response.cookies.set(AUTH_COOKIES.redirectContext, "", redirectContextClearOptions());
153
+ }
154
+
155
+ /** Server Components / Server Actions — clears redirect context in the current request store. */
156
+ export async function ClearRedirectContextStore() {
157
+ const cookieStore = await cookies();
158
+ cookieStore.set(AUTH_COOKIES.redirectContext, "", redirectContextClearOptions());
144
159
  }
@@ -1,4 +1,5 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
+ import { GetResponse } from "nexus-shared/interface";
2
3
  import { HttpPost } from "../services/http-services";
3
4
  import { AUTH_COOKIES, GetDecryptedRequestCookie, SetAuthCookies } from "./cookie-helpers";
4
5
  import { SSO_CONFIG } from "./sso-config";
@@ -6,17 +7,17 @@ import { SSOAuthResponse } from "./sso-interfaces";
6
7
 
7
8
  export async function RefreshRoute(req: NextRequest) {
8
9
  const refreshToken = GetDecryptedRequestCookie(req, AUTH_COOKIES.refreshToken);
9
- if (!refreshToken) return NextResponse.json({ error: "No refresh token" }, { status: 401 });
10
+ if (!refreshToken) return NextResponse.json(GetResponse.ERROR("No refresh token", "NJS_X1003"), { status: 401 });
10
11
 
11
12
  try {
12
13
  const refreshRes = await HttpPost(SSO_CONFIG.BACKEND_ENDPOINTS.REFRESH, { refreshToken, clientSystemName: SSO_CONFIG.BACKEND_CONFIG.CLIENT_SYSTEM_NAME });
13
- if (!refreshRes.isSuccess) return NextResponse.json({ error: "Refresh failed" }, { status: 401 });
14
+ if (!refreshRes.isSuccess) return NextResponse.json(GetResponse.ERROR("Refresh failed", "NJS_X1001"), { status: 401 });
14
15
 
15
16
  const newTokens = refreshRes.result as SSOAuthResponse;
16
- const response = NextResponse.json({ ok: true });
17
+ const response = NextResponse.json(GetResponse.SUCCESS(null, "Refresh successful"));
17
18
  SetAuthCookies(response, newTokens);
18
19
  return response;
19
20
  } catch {
20
- return NextResponse.json({ error: "Auth service unavailable" }, { status: 500 });
21
+ return NextResponse.json(GetResponse.ERROR("Auth service unavailable", "NJS_X1002"), { status: 500 });
21
22
  }
22
23
  }
@@ -3,10 +3,11 @@ import { EErrorCodes, EExceptionCategories } from "../interfaces/exception-inter
3
3
  import { GetResponse } from "../interfaces/http-interfaces";
4
4
  import { URLS } from "../nexus.environments";
5
5
  import { HttpPost } from "../services/http-services";
6
- import { AUTH_COOKIES, GetDecryptedRequestCookie, SetAuthCookies, SetSsoSessionCookie } from "./cookie-helpers";
6
+ import { AUTH_COOKIES, GetDecryptedRequestCookie, ResolvePostLoginRedirectUrl, SetAuthCookies, SetSsoSessionCookie } from "./cookie-helpers";
7
+ import { DecodeRedirectContext } from "./redirect-context-helpers";
7
8
  import { CreatePkcePair } from "./pkce-helpers";
8
9
  import { ClearRedirectContextCookie } from "./redirect-context-helpers";
9
- import { ExchangeAuthorizationCode, RequestAuthorizationCode } from "./sso-backend-flow";
10
+ import { ExchangeAuthorizationCode, GetClientConfiguration, RequestAuthorizationCode } from "./sso-backend-flow";
10
11
  import { BuildAuthenticationSignInUrl, SSO_CONFIG } from "./sso-config";
11
12
  import { ILoginRequest, ILoginResponse } from "./sso-interfaces";
12
13
 
@@ -58,12 +59,16 @@ export async function SignInPostRoute(req: NextRequest) {
58
59
 
59
60
  const signInResult = signInRes?.result as ILoginResponse;
60
61
 
61
- if (signInResult?.ssoSession) signInResult.redirectUrl = SSO_CONFIG.FRONTEND_ENDPOINTS.SSO_COMPLETE;
62
+ if (signInResult?.ssoSession) {
63
+ const redirectContext = DecodeRedirectContext(req.cookies.get(AUTH_COOKIES.redirectContext)?.value);
64
+ signInResult.redirectUrl = ResolvePostLoginRedirectUrl(!!redirectContext?.redirectUri);
65
+ }
62
66
 
63
67
  if (!signInRes.isSuccess || !signInResult?.ssoSession) return NextResponse.json(signInRes, { status: signInRes.code ?? 401 });
64
68
 
69
+ const ssoConfiguration = await GetClientConfiguration();
65
70
  const response = NextResponse.json(signInRes);
66
71
 
67
- SetSsoSessionCookie(response, signInResult.ssoSession, SSO_CONFIG.BACKEND_CONFIG.SSO_SESSION_MAX_AGE);
72
+ SetSsoSessionCookie(response, signInResult.ssoSession, ssoConfiguration.ssoSessionLifetime);
68
73
  return response;
69
74
  }
@@ -1,7 +1,7 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
2
  import { NEXUS_INFO, URLS } from "../nexus.environments";
3
3
  import { HttpPost } from "../services/http-services";
4
- import { AUTH_COOKIES, ClearAllAuthCookies, GetDecryptedRequestCookie } from "./cookie-helpers";
4
+ import { AUTH_COOKIES, ClearAuthCookies, GetDecryptedRequestCookie } from "./cookie-helpers";
5
5
  import { SanitizeReturnPath } from "./redirect-context-helpers";
6
6
  import { SSO_CONFIG } from "./sso-config";
7
7
 
@@ -20,6 +20,10 @@ function resolveReturnUrl(req: NextRequest): URL {
20
20
  return new URL(SanitizeReturnPath(returnPath), appBase);
21
21
  }
22
22
 
23
+ if (NEXUS_INFO.IS_ADMIN_MODULE) {
24
+ return new URL(URLS.SIGN_IN);
25
+ }
26
+
23
27
  return new URL(appBase);
24
28
  }
25
29
 
@@ -36,7 +40,7 @@ async function revokeServerSession(req: NextRequest) {
36
40
  export async function SignOutGetRoute(req: NextRequest) {
37
41
  await revokeServerSession(req);
38
42
  const response = NextResponse.redirect(resolveReturnUrl(req));
39
- ClearAllAuthCookies(response);
43
+ ClearAuthCookies(response);
40
44
  return response;
41
45
  }
42
46
 
@@ -48,6 +52,6 @@ export async function SignOutPostRoute(req: NextRequest) {
48
52
 
49
53
  await revokeServerSession(req);
50
54
  const response = NextResponse.json({ ok: true });
51
- ClearAllAuthCookies(response);
55
+ ClearAuthCookies(response);
52
56
  return response;
53
57
  }
@@ -1,6 +1,8 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
2
  import { HttpPost } from "../services/http-services";
3
- import { SetSsoSessionCookie } from "./cookie-helpers";
3
+ import { AUTH_COOKIES, ResolvePostLoginRedirectUrl, SetSsoSessionCookie } from "./cookie-helpers";
4
+ import { DecodeRedirectContext } from "./redirect-context-helpers";
5
+ import { GetClientConfiguration } from "./sso-backend-flow";
4
6
  import { SSO_CONFIG } from "./sso-config";
5
7
  import { ISignUpRequest } from "./sso-interfaces";
6
8
  import { ParseWrappedResult } from "./sso-response-helpers";
@@ -40,7 +42,16 @@ export async function SignUpPostRoute(req: NextRequest) {
40
42
  return NextResponse.json(signUpRes, { status: signUpRes.code ?? 400 });
41
43
  }
42
44
 
43
- const response = NextResponse.json(signUpRes);
44
- SetSsoSessionCookie(response, signUpResult.ssoSession, SSO_CONFIG.BACKEND_CONFIG.SSO_SESSION_MAX_AGE);
45
+ const ssoConfiguration = await GetClientConfiguration();
46
+ const redirectContext = DecodeRedirectContext(req.cookies.get(AUTH_COOKIES.redirectContext)?.value);
47
+
48
+ const response = NextResponse.json({
49
+ ...signUpRes,
50
+ result: {
51
+ ...signUpResult,
52
+ redirectUrl: ResolvePostLoginRedirectUrl(!!redirectContext?.redirectUri),
53
+ },
54
+ });
55
+ SetSsoSessionCookie(response, signUpResult.ssoSession, ssoConfiguration.ssoSessionLifetime);
45
56
  return response;
46
57
  }
@@ -1,23 +1,9 @@
1
- import { HttpPost } from "../services/http-services";
2
- import { PKCE_METHOD_S256, PkcePair } from "./pkce-helpers";
1
+ import { NEXUS_CONFIG } from "../nexus.environments";
2
+ import { HttpGet, HttpPost } from "../services/http-services";
3
3
  import { SSO_CONFIG } from "./sso-config";
4
- import { SSOAuthResponse } from "./sso-interfaces";
4
+ import { IClientApplication, PKCE_METHOD_S256, SSOAuthResponse, SsoExchangeInput, TokenExchangeInput } from "./sso-interfaces";
5
5
  import { ParseSsoCodeResponse, ParseTokenResponse } from "./sso-response-helpers";
6
6
 
7
- export type SsoExchangeInput = {
8
- ssoSession: string;
9
- redirectUri: string;
10
- state?: string;
11
- returnPath?: string;
12
- pkce: PkcePair;
13
- };
14
-
15
- export type TokenExchangeInput = {
16
- code: string;
17
- redirectUri: string;
18
- codeVerifier: string;
19
- };
20
-
21
7
  /** Server-only: request an authorization code using client policy + PKCE. */
22
8
  export async function RequestAuthorizationCode(input: SsoExchangeInput): Promise<string | null> {
23
9
  const ssoRes = await HttpPost(SSO_CONFIG.BACKEND_ENDPOINTS.SSO, {
@@ -43,3 +29,10 @@ export async function ExchangeAuthorizationCode(input: TokenExchangeInput): Prom
43
29
 
44
30
  return ParseTokenResponse(tokenRes);
45
31
  }
32
+
33
+ /** Server-only: get client configuration from the backend. */
34
+ export async function GetClientConfiguration(): Promise<IClientApplication> {
35
+ const clientConfigRes = await HttpGet(SSO_CONFIG.BACKEND_ENDPOINTS.CLIENT_CONFIG, null, NEXUS_CONFIG.DEFAULT_REVALIDATE_TIME_ONE_DAY);
36
+ if (!clientConfigRes.isSuccess) throw new Error("Failed to get client configuration");
37
+ return clientConfigRes.result;
38
+ }
@@ -1,10 +1,10 @@
1
1
  import { NextRequest, NextResponse } from "next/server";
2
2
  import { AUTH_COOKIES, GetDecryptedRequestCookie } from "./cookie-helpers";
3
3
  import { EncodeOAuthCallbackState } from "./oauth-callback-state";
4
- import { BuildAuthenticationSignInUrl } from "./sso-config";
5
4
  import { ClearRedirectContextCookie, DecodeRedirectContext } from "./redirect-context-helpers";
6
- import { PKCE_METHOD_S256, PkcePair } from "./pkce-helpers";
7
5
  import { RequestAuthorizationCode } from "./sso-backend-flow";
6
+ import { BuildAuthenticationSignInUrl, SSO_CONFIG } from "./sso-config";
7
+ import { PKCE_METHOD_S256, PkcePair } from "./sso-interfaces";
8
8
 
9
9
  function buildSignInRedirect(redirectContext: ReturnType<typeof DecodeRedirectContext>) {
10
10
  return new URL(BuildAuthenticationSignInUrl(redirectContext?.returnPath));
@@ -15,10 +15,14 @@ export async function SsoCompleteRoute(req: NextRequest) {
15
15
  const ssoSession = GetDecryptedRequestCookie(req, AUTH_COOKIES.ssoSession);
16
16
  const redirectContext = DecodeRedirectContext(req.cookies.get(AUTH_COOKIES.redirectContext)?.value);
17
17
 
18
- if (!ssoSession || !redirectContext?.redirectUri) {
18
+ if (!ssoSession) {
19
19
  return NextResponse.redirect(buildSignInRedirect(redirectContext));
20
20
  }
21
21
 
22
+ if (!redirectContext?.redirectUri) {
23
+ return NextResponse.redirect(new URL(SSO_CONFIG.FRONTEND_ENDPOINTS.SIGN_IN, req.url));
24
+ }
25
+
22
26
  const pkce: PkcePair = {
23
27
  verifier: redirectContext.pkceVerifier,
24
28
  challenge: redirectContext.codeChallenge,
@@ -2,9 +2,12 @@ import { APIS, URLS } from "nexus-shared";
2
2
 
3
3
  const _callbackPath = `${URLS.CURRENT}/api/auth/callback`;
4
4
 
5
+ // @ts-ignore
6
+ const processEnv = process.env;
7
+
5
8
  export const SSO_CONFIG = {
6
9
  COOKIE_CONFIG: {
7
- COOKIE_SECRET: process.env.SSO_COOKIE_SECRET as string,
10
+ COOKIE_SECRET: processEnv.SSO_COOKIE_SECRET as string,
8
11
  },
9
12
  BACKEND_ENDPOINTS: {
10
13
  SIGN_IN: `${APIS.AUTHENTICATION}/Authentication/SignIn`,
@@ -14,6 +17,7 @@ export const SSO_CONFIG = {
14
17
  REFRESH: `${APIS.AUTHENTICATION}/Authentication/Refresh`,
15
18
  SIGN_OUT: `${APIS.AUTHENTICATION}/Authentication/SignOut`,
16
19
  PROVIDERS: `${APIS.AUTHENTICATION}/Authentication/Providers`,
20
+ CLIENT_CONFIG: `${APIS.AUTHENTICATION}/Authentication/ClientConfig/${processEnv.AUTH_CLIENT_SYSTEM_NAME}`,
17
21
  FORGOT_PASSWORD: `${APIS.AUTHENTICATION}/Authentication/ForgotPassword`,
18
22
  RESET_PASSWORD: `${APIS.AUTHENTICATION}/Authentication/ResetPassword`,
19
23
  /** Used by VerifyAccessToken — returns 200 for a valid Bearer token, 401 otherwise. */
@@ -22,11 +26,9 @@ export const SSO_CONFIG = {
22
26
  },
23
27
  BACKEND_CONFIG: {
24
28
  /** Matches AuthenticationOptions.DefaultClientSystemName (NEXUS_WEB_APPLICATION_API). */
25
- CLIENT_SYSTEM_NAME: process.env.AUTH_CLIENT_SYSTEM_NAME as string,
26
- /** Matches ClientApplications.SsoSessionLifetime (30 minutes). */
27
- SSO_SESSION_MAX_AGE: process.env.SSO_SESSION_MAX_AGE as string,
29
+ CLIENT_SYSTEM_NAME: processEnv.AUTH_CLIENT_SYSTEM_NAME as string,
28
30
  /** How long redirect_uri/state survive in a secure httpOnly cookie on the auth app (seconds). */
29
- REDIRECT_CONTEXT_MAX_AGE: process.env.REDIRECT_CONTEXT_MAX_AGE as string,
31
+ REDIRECT_CONTEXT_MAX_AGE: processEnv.REDIRECT_CONTEXT_MAX_AGE as string,
30
32
  },
31
33
  FRONTEND_ENDPOINTS: {
32
34
  CALLBACK: _callbackPath,
@@ -1,4 +1,7 @@
1
1
  import { UN } from "../interfaces/type-interfaces";
2
+
3
+ export const PKCE_METHOD_S256 = "S256";
4
+
2
5
  export interface SSOAuthResponse {
3
6
  accessToken: string;
4
7
  refreshToken: string;
@@ -8,9 +11,9 @@ export interface SSOAuthResponse {
8
11
  }
9
12
 
10
13
  export interface CookieInfo {
11
- ssoSession: string;
12
- accessToken: string | UN;
13
- refreshToken: string | UN;
14
+ ssoSession?: string;
15
+ accessToken?: string | UN;
16
+ refreshToken?: string;
14
17
  }
15
18
 
16
19
  export interface IRedirectContext {
@@ -66,3 +69,31 @@ export interface IDemoUserInfo {
66
69
  role: string;
67
70
  passwordHint: string;
68
71
  }
72
+
73
+ export type SsoExchangeInput = {
74
+ ssoSession: string;
75
+ redirectUri: string;
76
+ state?: string;
77
+ returnPath?: string;
78
+ pkce: PkcePair;
79
+ };
80
+
81
+ export type TokenExchangeInput = {
82
+ code: string;
83
+ redirectUri: string;
84
+ codeVerifier: string;
85
+ };
86
+ export type PkcePair = {
87
+ verifier: string;
88
+ challenge: string;
89
+ method: typeof PKCE_METHOD_S256;
90
+ };
91
+
92
+ export interface IClientApplication {
93
+ requirePkce: boolean;
94
+ accessTokenLifetime: number;
95
+ refreshTokenLifetime: number;
96
+ authorizationCodeLifetime: number;
97
+ ssoSessionLifetime: number;
98
+ allowOfflineAccess: boolean;
99
+ }
@@ -0,0 +1,42 @@
1
+ :root {
2
+ --Border-Size: 0.03rem;
3
+ }
4
+
5
+ #inch-grid,
6
+ #cm-grid,
7
+ #mm-grid,
8
+ #half-mm-grid,
9
+ #quarter-mm-grid {
10
+ position: fixed;
11
+ top: 0;
12
+ left: 0;
13
+ z-index: 1000000;
14
+ width: 100%;
15
+ height: 100vh;
16
+ pointer-events: none;
17
+ }
18
+
19
+ #inch-grid {
20
+ background-image: repeating-linear-gradient(0deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 1in), repeating-linear-gradient(90deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 1in);
21
+ background-size: 100% 1in, 1in 1in;
22
+ display: none;
23
+ }
24
+
25
+ #cm-grid {
26
+ background-image: repeating-linear-gradient(0deg, rgb(70, 70, 70), rgb(70, 70, 700) var(--Border-Size), transparent var(--Border-Size), transparent 1cm), repeating-linear-gradient(90deg, rgb(70, 70, 700), rgb(700, 700, 700) var(--Border-Size), transparent var(--Border-Size), transparent 1cm);
27
+ background-size: 100% 1cm, 1cm 1cm;
28
+ }
29
+
30
+ #mm-grid {
31
+ background-image: repeating-linear-gradient(0deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 1cm), repeating-linear-gradient(90deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 5mm);
32
+ background-size: 100% 5mm, 5mm 5mm;
33
+ }
34
+ #half-mm-grid {
35
+ background-image: repeating-linear-gradient(0deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 1cm), repeating-linear-gradient(90deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 2.5mm);
36
+ background-size: 100% 2.5mm, 2.5mm 2.5mm;
37
+ }
38
+
39
+ #quarter-mm-grid {
40
+ background-image: repeating-linear-gradient(0deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 1cm), repeating-linear-gradient(90deg, rgb(200, 200, 200), rgb(200, 200, 200) var(--Border-Size), transparent var(--Border-Size), transparent 1.25mm);
41
+ background-size: 100% 1.25mm, 1.25mm 1.25mm;
42
+ }
@@ -22,6 +22,7 @@
22
22
  transition: var(--ANIM);
23
23
  font-size: var(--IS);
24
24
  pointer-events: none !important;
25
+ --ionicon-stroke-width: 2rem;
25
26
  }
26
27
 
27
28
  .ib.h:hover > .icon {
@@ -1,18 +1,47 @@
1
+ :root {
2
+ --ACTIVE_BACKGROUND_COLOR: var(--B1);
3
+ --ACTIVE_BORDER_COLOR: var(--B20);
4
+ --ACTIVE_TEXT_COLOR: var(--T1);
5
+ }
6
+ .item .ho1 {
7
+ opacity: 0;
8
+ }
9
+
1
10
  .ho1:hover {
2
11
  opacity: 1;
3
12
  }
4
- .btn.active {
5
- font-weight: 500;
6
- }
7
- .btn.active {
13
+ .btn.active,
14
+ .btn.left-active {
8
15
  background-color: var(--ACTIVE_BACKGROUND_COLOR) !important;
9
16
  pointer-events: none;
17
+ border-radius: 0 !important;
18
+ opacity: 1 !important;
10
19
  }
11
- .btn.active::after {
20
+ .btn.active::after,
21
+ .btn.left-active::after {
12
22
  content: " ";
13
23
  position: absolute;
14
24
  width: 100%;
15
25
  height: var(--BRD2);
16
26
  bottom: 0;
27
+ left: 0;
17
28
  background-color: var(--ACTIVE_BORDER_COLOR);
18
29
  }
30
+
31
+ .btn.left-active::after {
32
+ width: calc(var(--BRD2) * 3) !important;
33
+ height: 100% !important;
34
+ bottom: unset;
35
+ top: 0;
36
+ }
37
+
38
+ .btn.active,
39
+ .btn.left-active,
40
+ .btn.active span,
41
+ .btn.active .icon,
42
+ .btn.left-active .icon,
43
+ .btn.left-active span {
44
+ color: var(--ACTIVE_TEXT_COLOR) !important;
45
+ font-weight: 600 !important;
46
+ opacity: 1 !important;
47
+ }