@ncim/sdk 0.1.0 → 0.2.0
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/fesm2022/ncim-sdk-core.mjs +4118 -1
- package/fesm2022/ncim-sdk-core.mjs.map +1 -1
- package/fesm2022/ncim-sdk-features-ncim-sdk-features-YQVsqseZ.mjs +2419 -0
- package/fesm2022/ncim-sdk-features-ncim-sdk-features-YQVsqseZ.mjs.map +1 -0
- package/fesm2022/ncim-sdk-features-sso-callback-DLX42VOO.mjs +110 -0
- package/fesm2022/ncim-sdk-features-sso-callback-DLX42VOO.mjs.map +1 -0
- package/fesm2022/ncim-sdk-features-sso-error-CBlw1Gla.mjs +73 -0
- package/fesm2022/ncim-sdk-features-sso-error-CBlw1Gla.mjs.map +1 -0
- package/fesm2022/ncim-sdk-features.mjs +2 -5
- package/fesm2022/ncim-sdk-features.mjs.map +1 -1
- package/fesm2022/ncim-sdk-ncim-sdk-DPJwZ1er.mjs +13378 -0
- package/fesm2022/ncim-sdk-ncim-sdk-DPJwZ1er.mjs.map +1 -0
- package/fesm2022/ncim-sdk-sso-callback-DxhXnPAG.mjs +110 -0
- package/fesm2022/ncim-sdk-sso-callback-DxhXnPAG.mjs.map +1 -0
- package/fesm2022/ncim-sdk-sso-error-CVdCgF23.mjs +73 -0
- package/fesm2022/ncim-sdk-sso-error-CVdCgF23.mjs.map +1 -0
- package/fesm2022/ncim-sdk-state.mjs +47 -1
- package/fesm2022/ncim-sdk-state.mjs.map +1 -1
- package/fesm2022/ncim-sdk-ui.mjs +6474 -1
- package/fesm2022/ncim-sdk-ui.mjs.map +1 -1
- package/fesm2022/ncim-sdk.mjs +1 -23
- package/fesm2022/ncim-sdk.mjs.map +1 -1
- package/package.json +1 -1
- package/types/ncim-sdk-core.d.ts +1738 -1
- package/types/ncim-sdk-features.d.ts +1018 -1
- package/types/ncim-sdk-state.d.ts +56 -1
- package/types/ncim-sdk-ui.d.ts +3128 -1
- package/types/ncim-sdk.d.ts +6623 -8
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { Router, ActivatedRoute } from '@angular/router';
|
|
5
|
+
import { AuthService, SSO_CALLBACK_PARAMS_KEY } from './ncim-sdk-core.mjs';
|
|
6
|
+
import { ROUTE_PATHS } from './ncim-sdk-core.mjs';
|
|
7
|
+
import { SsoCallbackView } from './ncim-sdk-ui.mjs';
|
|
8
|
+
import { S as SSO_ERROR_PARAM, a as SSO_ERROR_DESCRIPTION_PARAM, b as buildSsoErrorQueryParams } from './ncim-sdk-ncim-sdk-DPJwZ1er.mjs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Smart container for the MOMRAH SSO redirect callback (/sso-callback).
|
|
12
|
+
*
|
|
13
|
+
* Handles redirect logic; delegates UI to dumb SsoCallbackView.
|
|
14
|
+
* By the time this component is created, APP_INITIALIZER has already processed
|
|
15
|
+
* the authorization code via OidcAuthService.initialize(). This component:
|
|
16
|
+
* 1. Restores the full callback params (code, scope, state, session_state, iss)
|
|
17
|
+
* from localStorage → restores to the URL query string.
|
|
18
|
+
* 2. Checks for an error query param (e.g. ?error=access_denied) → redirects to /sso-error
|
|
19
|
+
* 3. Exchanges the OIDC access token for a backend JWT via POST /auth/sso-callback
|
|
20
|
+
* 4. On success → navigates to the pre-login redirect URL (or Dashboard as fallback)
|
|
21
|
+
* 5. On failure → redirects to /sso-error with server_error code
|
|
22
|
+
*
|
|
23
|
+
* Any app that uses `ssoCallbackRoute()` from `@libs/features` will lazy-load
|
|
24
|
+
* this component automatically.
|
|
25
|
+
*/
|
|
26
|
+
class SsoCallback {
|
|
27
|
+
router = inject(Router);
|
|
28
|
+
authService = inject(AuthService);
|
|
29
|
+
route = inject(ActivatedRoute);
|
|
30
|
+
/**
|
|
31
|
+
* True while the backend token-exchange POST is in-flight.
|
|
32
|
+
* Drives the "Verifying identity…" message in the view — more accurate
|
|
33
|
+
* than "Redirecting…" which only applies once the exchange succeeds.
|
|
34
|
+
*/
|
|
35
|
+
isVerifying = signal(true, ...(ngDevMode ? [{ debugName: "isVerifying" }] : []));
|
|
36
|
+
constructor() {
|
|
37
|
+
// this.handleCallback();
|
|
38
|
+
}
|
|
39
|
+
handleCallback() {
|
|
40
|
+
// Restore and persist the callback params that tryLogin() stripped from the URL.
|
|
41
|
+
const savedParams = this.restoreCallbackParams();
|
|
42
|
+
// ── Error from SSO server (e.g. access_denied, login_required) ──────────────
|
|
43
|
+
// Check both the live route params (iss still present) and the saved snapshot.
|
|
44
|
+
const error = this.route.snapshot.queryParamMap.get(SSO_ERROR_PARAM) ?? savedParams?.[SSO_ERROR_PARAM] ?? null;
|
|
45
|
+
if (error) {
|
|
46
|
+
const description = this.route.snapshot.queryParamMap.get(SSO_ERROR_DESCRIPTION_PARAM) ??
|
|
47
|
+
savedParams?.[SSO_ERROR_DESCRIPTION_PARAM] ??
|
|
48
|
+
null;
|
|
49
|
+
this.redirectToError(error, description);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
// ── Exchange OIDC access token for backend JWT ────────────────────────────────
|
|
53
|
+
this.authService
|
|
54
|
+
.completeSsoCallback()
|
|
55
|
+
.pipe(takeUntilDestroyed())
|
|
56
|
+
.subscribe({
|
|
57
|
+
next: () => {
|
|
58
|
+
// Token exchange succeeded — switch message to "Redirecting…" briefly.
|
|
59
|
+
this.isVerifying.set(false);
|
|
60
|
+
// Restore user to the page they were on before SSO login, or Dashboard.
|
|
61
|
+
// Validate that the stored URL is a local path to prevent open redirects.
|
|
62
|
+
const redirectUrl = this.authService.getAndClearRedirectUrl();
|
|
63
|
+
const safeUrl = redirectUrl && redirectUrl.startsWith('/') && !redirectUrl.startsWith('//') && !redirectUrl.includes('://')
|
|
64
|
+
? redirectUrl
|
|
65
|
+
: ROUTE_PATHS.DASHBOARD;
|
|
66
|
+
void this.router.navigateByUrl(safeUrl, { replaceUrl: true });
|
|
67
|
+
},
|
|
68
|
+
// Backend rejected the token or network error → send user to error page.
|
|
69
|
+
error: () => this.redirectToError('server_error', null),
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Reads the param snapshot written by OidcAuthService before tryLogin() ran,
|
|
74
|
+
* keeps it in localStorage, and restores the full query string to the URL
|
|
75
|
+
* so the callback URL shows all original params (code, scope, state, session_state, iss).
|
|
76
|
+
*/
|
|
77
|
+
restoreCallbackParams() {
|
|
78
|
+
const raw = localStorage.getItem(SSO_CALLBACK_PARAMS_KEY);
|
|
79
|
+
if (!raw) {
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
let params;
|
|
83
|
+
try {
|
|
84
|
+
params = JSON.parse(raw);
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
// Restore full query string to the URL (replaceUrl so no history entry is added).
|
|
90
|
+
void this.router.navigate([], {
|
|
91
|
+
relativeTo: this.route,
|
|
92
|
+
queryParams: params,
|
|
93
|
+
replaceUrl: true,
|
|
94
|
+
});
|
|
95
|
+
return params;
|
|
96
|
+
}
|
|
97
|
+
redirectToError(error, description) {
|
|
98
|
+
const queryParams = buildSsoErrorQueryParams(error, description);
|
|
99
|
+
void this.router.navigate([ROUTE_PATHS.SSO_ERROR], { queryParams, replaceUrl: true });
|
|
100
|
+
}
|
|
101
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SsoCallback, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
102
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: SsoCallback, isStandalone: true, selector: "ncim-sso-callback", ngImport: i0, template: "<ncim-sso-callback-view\n [titleKey]=\"isVerifying() ? 'AUTH.SSO.VERIFYING' : 'AUTH.SSO.REDIRECTING'\"\n [messageKey]=\"isVerifying() ? 'AUTH.SSO.VERIFYING_DESC' : 'AUTH.SSO.REDIRECTING_DESC'\"\n/>\n", dependencies: [{ kind: "component", type: SsoCallbackView, selector: "ncim-sso-callback-view", inputs: ["titleKey", "messageKey", "spinnerSize"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
103
|
+
}
|
|
104
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SsoCallback, decorators: [{
|
|
105
|
+
type: Component,
|
|
106
|
+
args: [{ selector: 'ncim-sso-callback', imports: [SsoCallbackView], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ncim-sso-callback-view\n [titleKey]=\"isVerifying() ? 'AUTH.SSO.VERIFYING' : 'AUTH.SSO.REDIRECTING'\"\n [messageKey]=\"isVerifying() ? 'AUTH.SSO.VERIFYING_DESC' : 'AUTH.SSO.REDIRECTING_DESC'\"\n/>\n" }]
|
|
107
|
+
}], ctorParameters: () => [] });
|
|
108
|
+
|
|
109
|
+
export { SsoCallback };
|
|
110
|
+
//# sourceMappingURL=ncim-sdk-sso-callback-DxhXnPAG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ncim-sdk-sso-callback-DxhXnPAG.mjs","sources":["../../../../libs/features/src/lib/sso/components/sso-callback/sso-callback.ts","../../../../libs/features/src/lib/sso/components/sso-callback/sso-callback.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, inject, signal } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { AuthService, SSO_CALLBACK_PARAMS_KEY } from '@libs/core/services';\nimport { ROUTE_PATHS } from '@libs/core/constants';\nimport { SsoCallbackView } from '@libs/ui-components/sso';\nimport { buildSsoErrorQueryParams, SSO_ERROR_DESCRIPTION_PARAM, SSO_ERROR_PARAM } from '../../utils/sso-query-params';\n\n/**\n * Smart container for the MOMRAH SSO redirect callback (/sso-callback).\n *\n * Handles redirect logic; delegates UI to dumb SsoCallbackView.\n * By the time this component is created, APP_INITIALIZER has already processed\n * the authorization code via OidcAuthService.initialize(). This component:\n * 1. Restores the full callback params (code, scope, state, session_state, iss)\n * from localStorage → restores to the URL query string.\n * 2. Checks for an error query param (e.g. ?error=access_denied) → redirects to /sso-error\n * 3. Exchanges the OIDC access token for a backend JWT via POST /auth/sso-callback\n * 4. On success → navigates to the pre-login redirect URL (or Dashboard as fallback)\n * 5. On failure → redirects to /sso-error with server_error code\n *\n * Any app that uses `ssoCallbackRoute()` from `@libs/features` will lazy-load\n * this component automatically.\n */\n@Component({\n selector: 'ncim-sso-callback',\n imports: [SsoCallbackView],\n templateUrl: './sso-callback.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SsoCallback {\n private readonly router = inject(Router);\n private readonly authService = inject(AuthService);\n private readonly route = inject(ActivatedRoute);\n\n /**\n * True while the backend token-exchange POST is in-flight.\n * Drives the \"Verifying identity…\" message in the view — more accurate\n * than \"Redirecting…\" which only applies once the exchange succeeds.\n */\n readonly isVerifying = signal(true);\n\n constructor() {\n // this.handleCallback();\n }\n\n private handleCallback(): void {\n // Restore and persist the callback params that tryLogin() stripped from the URL.\n const savedParams = this.restoreCallbackParams();\n\n // ── Error from SSO server (e.g. access_denied, login_required) ──────────────\n // Check both the live route params (iss still present) and the saved snapshot.\n const error = this.route.snapshot.queryParamMap.get(SSO_ERROR_PARAM) ?? savedParams?.[SSO_ERROR_PARAM] ?? null;\n\n if (error) {\n const description =\n this.route.snapshot.queryParamMap.get(SSO_ERROR_DESCRIPTION_PARAM) ??\n savedParams?.[SSO_ERROR_DESCRIPTION_PARAM] ??\n null;\n this.redirectToError(error, description);\n return;\n }\n\n // ── Exchange OIDC access token for backend JWT ────────────────────────────────\n this.authService\n .completeSsoCallback()\n .pipe(takeUntilDestroyed())\n .subscribe({\n next: () => {\n // Token exchange succeeded — switch message to \"Redirecting…\" briefly.\n this.isVerifying.set(false);\n // Restore user to the page they were on before SSO login, or Dashboard.\n // Validate that the stored URL is a local path to prevent open redirects.\n const redirectUrl = this.authService.getAndClearRedirectUrl();\n const safeUrl =\n redirectUrl && redirectUrl.startsWith('/') && !redirectUrl.startsWith('//') && !redirectUrl.includes('://')\n ? redirectUrl\n : ROUTE_PATHS.DASHBOARD;\n void this.router.navigateByUrl(safeUrl, { replaceUrl: true });\n },\n // Backend rejected the token or network error → send user to error page.\n error: () => this.redirectToError('server_error', null),\n });\n }\n\n /**\n * Reads the param snapshot written by OidcAuthService before tryLogin() ran,\n * keeps it in localStorage, and restores the full query string to the URL\n * so the callback URL shows all original params (code, scope, state, session_state, iss).\n */\n private restoreCallbackParams(): Record<string, string> | null {\n const raw = localStorage.getItem(SSO_CALLBACK_PARAMS_KEY);\n if (!raw) {\n return null;\n }\n\n let params: Record<string, string>;\n try {\n params = JSON.parse(raw) as Record<string, string>;\n } catch {\n return null;\n }\n\n // Restore full query string to the URL (replaceUrl so no history entry is added).\n void this.router.navigate([], {\n relativeTo: this.route,\n queryParams: params,\n replaceUrl: true,\n });\n\n return params;\n }\n\n private redirectToError(error: string, description: string | null): void {\n const queryParams = buildSsoErrorQueryParams(error, description);\n void this.router.navigate([ROUTE_PATHS.SSO_ERROR], { queryParams, replaceUrl: true });\n }\n}\n","<ncim-sso-callback-view\n [titleKey]=\"isVerifying() ? 'AUTH.SSO.VERIFYING' : 'AUTH.SSO.REDIRECTING'\"\n [messageKey]=\"isVerifying() ? 'AUTH.SSO.VERIFYING_DESC' : 'AUTH.SSO.REDIRECTING_DESC'\"\n/>\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, computed, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { toSignal } from '@angular/core/rxjs-interop';
|
|
4
|
+
import { ActivatedRoute } from '@angular/router';
|
|
5
|
+
import { AuthService } from './ncim-sdk-core.mjs';
|
|
6
|
+
import { ROUTE_PATHS } from './ncim-sdk-core.mjs';
|
|
7
|
+
import { SsoErrorDisplay } from './ncim-sdk-ui.mjs';
|
|
8
|
+
import { c as SSO_UNKNOWN_ERROR_CODE, S as SSO_ERROR_PARAM, a as SSO_ERROR_DESCRIPTION_PARAM, g as getSsoErrorMessageKey } from './ncim-sdk-ncim-sdk-DPJwZ1er.mjs';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Internal/generic error codes generated by the app itself — not meaningful to
|
|
12
|
+
* show as a raw badge to users (e.g. "server_error", "unknown_error").
|
|
13
|
+
* Only codes sent directly by the SSO server (access_denied, login_required, …)
|
|
14
|
+
* are shown as badges.
|
|
15
|
+
*/
|
|
16
|
+
const INTERNAL_ERROR_CODES = new Set(['server_error', 'unknown_error']);
|
|
17
|
+
/**
|
|
18
|
+
* Errors that the user can recover from by simply retrying the SSO flow.
|
|
19
|
+
* Non-retryable errors (access_denied, unauthorized_client, …) indicate a
|
|
20
|
+
* permanent problem that retrying will not fix.
|
|
21
|
+
*/
|
|
22
|
+
const RETRYABLE_ERROR_CODES = new Set([
|
|
23
|
+
'login_required', // session expired — login again
|
|
24
|
+
'interaction_required', // user action needed — retry triggers it
|
|
25
|
+
'consent_required', // user must grant consent — retry asks again
|
|
26
|
+
'invalid_grant', // code expired — fresh retry starts new flow
|
|
27
|
+
'temporarily_unavailable', // server busy — retry may succeed
|
|
28
|
+
]);
|
|
29
|
+
/**
|
|
30
|
+
* Smart container for SSO error display.
|
|
31
|
+
* Reads route params and passes data to the dumb SsoErrorDisplay component.
|
|
32
|
+
*
|
|
33
|
+
* Displayed when the MOMRAH SSO server returns an error on the callback,
|
|
34
|
+
* e.g. error=access_denied, error=login_required, or an expired/reused code.
|
|
35
|
+
*/
|
|
36
|
+
class SsoError {
|
|
37
|
+
route = inject(ActivatedRoute);
|
|
38
|
+
authService = inject(AuthService);
|
|
39
|
+
queryParamMap = toSignal(this.route.queryParamMap, {
|
|
40
|
+
initialValue: null,
|
|
41
|
+
});
|
|
42
|
+
errorCode = computed(() => this.queryParamMap()?.get(SSO_ERROR_PARAM) ?? SSO_UNKNOWN_ERROR_CODE, ...(ngDevMode ? [{ debugName: "errorCode" }] : []));
|
|
43
|
+
errorDescription = computed(() => this.queryParamMap()?.get(SSO_ERROR_DESCRIPTION_PARAM) ?? null, ...(ngDevMode ? [{ debugName: "errorDescription" }] : []));
|
|
44
|
+
errorMessageKey = computed(() => getSsoErrorMessageKey(this.errorCode()), ...(ngDevMode ? [{ debugName: "errorMessageKey" }] : []));
|
|
45
|
+
/**
|
|
46
|
+
* Show the error code badge only for codes sent directly by the SSO server.
|
|
47
|
+
* Internal codes (server_error, unknown_error) are not surfaced as raw strings.
|
|
48
|
+
*/
|
|
49
|
+
showCodeBadge = computed(() => {
|
|
50
|
+
const code = this.errorCode();
|
|
51
|
+
return this.queryParamMap()?.has(SSO_ERROR_PARAM) === true && !INTERNAL_ERROR_CODES.has(code);
|
|
52
|
+
}, ...(ngDevMode ? [{ debugName: "showCodeBadge" }] : []));
|
|
53
|
+
/**
|
|
54
|
+
* True when SSO is enabled and the error is recoverable by retrying the login flow.
|
|
55
|
+
* Non-retryable errors (access_denied, unauthorized_client, …) only show the back link.
|
|
56
|
+
*/
|
|
57
|
+
canRetry = computed(() => this.authService.isSsoEnabled && RETRYABLE_ERROR_CODES.has(this.errorCode()), ...(ngDevMode ? [{ debugName: "canRetry" }] : []));
|
|
58
|
+
/** Login route path for the "Back to login" link. */
|
|
59
|
+
loginPath = ROUTE_PATHS.AUTH_LOGIN;
|
|
60
|
+
/** Restart the SSO authorization code flow from the error page. */
|
|
61
|
+
handleRetry() {
|
|
62
|
+
this.authService.loginWithSso();
|
|
63
|
+
}
|
|
64
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SsoError, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
65
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.1.3", type: SsoError, isStandalone: true, selector: "ncim-sso-error", ngImport: i0, template: "<ncim-sso-error-display\n [errorCode]=\"errorCode()\"\n [errorDescription]=\"errorDescription()\"\n [errorMessageKey]=\"errorMessageKey()\"\n [showCodeBadge]=\"showCodeBadge()\"\n [showRetryButton]=\"canRetry()\"\n [loginPath]=\"loginPath\"\n (retryClick)=\"handleRetry()\"\n/>\n", dependencies: [{ kind: "component", type: SsoErrorDisplay, selector: "ncim-sso-error-display", inputs: ["errorCode", "errorDescription", "errorMessageKey", "showCodeBadge", "showRetryButton", "loginPath", "titleKey", "codeLabelKey", "backToLoginKey", "retryLabelKey"], outputs: ["retryClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
66
|
+
}
|
|
67
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: SsoError, decorators: [{
|
|
68
|
+
type: Component,
|
|
69
|
+
args: [{ selector: 'ncim-sso-error', imports: [SsoErrorDisplay], changeDetection: ChangeDetectionStrategy.OnPush, template: "<ncim-sso-error-display\n [errorCode]=\"errorCode()\"\n [errorDescription]=\"errorDescription()\"\n [errorMessageKey]=\"errorMessageKey()\"\n [showCodeBadge]=\"showCodeBadge()\"\n [showRetryButton]=\"canRetry()\"\n [loginPath]=\"loginPath\"\n (retryClick)=\"handleRetry()\"\n/>\n" }]
|
|
70
|
+
}] });
|
|
71
|
+
|
|
72
|
+
export { SsoError };
|
|
73
|
+
//# sourceMappingURL=ncim-sdk-sso-error-CVdCgF23.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ncim-sdk-sso-error-CVdCgF23.mjs","sources":["../../../../libs/features/src/lib/sso/components/sso-error/sso-error.ts","../../../../libs/features/src/lib/sso/components/sso-error/sso-error.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, inject } from '@angular/core';\nimport { toSignal } from '@angular/core/rxjs-interop';\nimport { ActivatedRoute } from '@angular/router';\nimport { AuthService } from '@libs/core/services';\nimport { ROUTE_PATHS } from '@libs/core/constants';\nimport { SsoErrorDisplay } from '@libs/ui-components/sso';\nimport { SSO_ERROR_DESCRIPTION_PARAM, SSO_ERROR_PARAM } from '../../utils/sso-query-params';\nimport { getSsoErrorMessageKey, SSO_UNKNOWN_ERROR_CODE } from '../../constants/sso-error-codes';\n\n/**\n * Internal/generic error codes generated by the app itself — not meaningful to\n * show as a raw badge to users (e.g. \"server_error\", \"unknown_error\").\n * Only codes sent directly by the SSO server (access_denied, login_required, …)\n * are shown as badges.\n */\nconst INTERNAL_ERROR_CODES = new Set(['server_error', 'unknown_error']);\n\n/**\n * Errors that the user can recover from by simply retrying the SSO flow.\n * Non-retryable errors (access_denied, unauthorized_client, …) indicate a\n * permanent problem that retrying will not fix.\n */\nconst RETRYABLE_ERROR_CODES = new Set([\n 'login_required', // session expired — login again\n 'interaction_required', // user action needed — retry triggers it\n 'consent_required', // user must grant consent — retry asks again\n 'invalid_grant', // code expired — fresh retry starts new flow\n 'temporarily_unavailable', // server busy — retry may succeed\n]);\n\n/**\n * Smart container for SSO error display.\n * Reads route params and passes data to the dumb SsoErrorDisplay component.\n *\n * Displayed when the MOMRAH SSO server returns an error on the callback,\n * e.g. error=access_denied, error=login_required, or an expired/reused code.\n */\n@Component({\n selector: 'ncim-sso-error',\n imports: [SsoErrorDisplay],\n templateUrl: './sso-error.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class SsoError {\n private readonly route = inject(ActivatedRoute);\n private readonly authService = inject(AuthService);\n\n private readonly queryParamMap = toSignal(this.route.queryParamMap, {\n initialValue: null,\n });\n\n readonly errorCode = computed(() => this.queryParamMap()?.get(SSO_ERROR_PARAM) ?? SSO_UNKNOWN_ERROR_CODE);\n\n readonly errorDescription = computed(() => this.queryParamMap()?.get(SSO_ERROR_DESCRIPTION_PARAM) ?? null);\n\n readonly errorMessageKey = computed(() => getSsoErrorMessageKey(this.errorCode()));\n\n /**\n * Show the error code badge only for codes sent directly by the SSO server.\n * Internal codes (server_error, unknown_error) are not surfaced as raw strings.\n */\n readonly showCodeBadge = computed(() => {\n const code = this.errorCode();\n return this.queryParamMap()?.has(SSO_ERROR_PARAM) === true && !INTERNAL_ERROR_CODES.has(code);\n });\n\n /**\n * True when SSO is enabled and the error is recoverable by retrying the login flow.\n * Non-retryable errors (access_denied, unauthorized_client, …) only show the back link.\n */\n readonly canRetry = computed(() => this.authService.isSsoEnabled && RETRYABLE_ERROR_CODES.has(this.errorCode()));\n\n /** Login route path for the \"Back to login\" link. */\n protected readonly loginPath = ROUTE_PATHS.AUTH_LOGIN;\n\n /** Restart the SSO authorization code flow from the error page. */\n handleRetry(): void {\n this.authService.loginWithSso();\n }\n}\n","<ncim-sso-error-display\n [errorCode]=\"errorCode()\"\n [errorDescription]=\"errorDescription()\"\n [errorMessageKey]=\"errorMessageKey()\"\n [showCodeBadge]=\"showCodeBadge()\"\n [showRetryButton]=\"canRetry()\"\n [loginPath]=\"loginPath\"\n (retryClick)=\"handleRetry()\"\n/>\n"],"names":[],"mappings":";;;;;;;;;AASA;;;;;AAKG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC,CAAC,cAAc,EAAE,eAAe,CAAC,CAAC;AAEvE;;;;AAIG;AACH,MAAM,qBAAqB,GAAG,IAAI,GAAG,CAAC;AACpC,IAAA,gBAAgB;AAChB,IAAA,sBAAsB;AACtB,IAAA,kBAAkB;AAClB,IAAA,eAAe;AACf,IAAA,yBAAyB;AAC1B,CAAA,CAAC;AAEF;;;;;;AAMG;MAOU,QAAQ,CAAA;AACF,IAAA,KAAK,GAAG,MAAM,CAAC,cAAc,CAAC;AAC9B,IAAA,WAAW,GAAG,MAAM,CAAC,WAAW,CAAC;IAEjC,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,EAAE;AAClE,QAAA,YAAY,EAAE,IAAI;AACnB,KAAA,CAAC;AAEO,IAAA,SAAS,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,sBAAsB,qDAAC;AAEhG,IAAA,gBAAgB,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,CAAC,2BAA2B,CAAC,IAAI,IAAI,4DAAC;AAEjG,IAAA,eAAe,GAAG,QAAQ,CAAC,MAAM,qBAAqB,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,2DAAC;AAElF;;;AAGG;AACM,IAAA,aAAa,GAAG,QAAQ,CAAC,MAAK;AACrC,QAAA,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE;AAC7B,QAAA,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,CAAC,eAAe,CAAC,KAAK,IAAI,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC;AAC/F,IAAA,CAAC,yDAAC;AAEF;;;AAGG;IACM,QAAQ,GAAG,QAAQ,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,YAAY,IAAI,qBAAqB,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC,EAAA,IAAA,SAAA,GAAA,CAAA,EAAA,SAAA,EAAA,UAAA,EAAA,CAAA,GAAA,EAAA,CAAA,CAAC;;AAG7F,IAAA,SAAS,GAAG,WAAW,CAAC,UAAU;;IAGrD,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,WAAW,CAAC,YAAY,EAAE;IACjC;uGAnCW,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAR,QAAQ,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,EC3CrB,gSASA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,ED8BY,eAAe,EAAA,QAAA,EAAA,wBAAA,EAAA,MAAA,EAAA,CAAA,WAAA,EAAA,kBAAA,EAAA,iBAAA,EAAA,eAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,cAAA,EAAA,gBAAA,EAAA,eAAA,CAAA,EAAA,OAAA,EAAA,CAAA,YAAA,CAAA,EAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAId,QAAQ,EAAA,UAAA,EAAA,CAAA;kBANpB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,gBAAgB,WACjB,CAAC,eAAe,CAAC,EAAA,eAAA,EAET,uBAAuB,CAAC,MAAM,EAAA,QAAA,EAAA,gSAAA,EAAA;;;;;"}
|
|
@@ -1,6 +1,52 @@
|
|
|
1
|
-
|
|
1
|
+
import { createActionGroup, emptyProps, props, createFeature, createReducer, on } from '@ngrx/store';
|
|
2
|
+
|
|
3
|
+
/** User feature actions (load, set/clear current user). */
|
|
4
|
+
const UserActions = createActionGroup({
|
|
5
|
+
source: 'User',
|
|
6
|
+
events: {
|
|
7
|
+
'Load Users': emptyProps(),
|
|
8
|
+
'Load Users Success': props(),
|
|
9
|
+
'Load Users Failure': props(),
|
|
10
|
+
'Set Current User': props(),
|
|
11
|
+
'Clear Current User': emptyProps(),
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
const initialState = {
|
|
16
|
+
users: [],
|
|
17
|
+
currentUser: null,
|
|
18
|
+
loading: false,
|
|
19
|
+
error: null,
|
|
20
|
+
};
|
|
21
|
+
const userFeature = createFeature({
|
|
22
|
+
name: 'user',
|
|
23
|
+
reducer: createReducer(initialState, on(UserActions.loadUsers, state => ({
|
|
24
|
+
...state,
|
|
25
|
+
loading: true,
|
|
26
|
+
error: null,
|
|
27
|
+
})), on(UserActions.loadUsersSuccess, (state, { users }) => ({
|
|
28
|
+
...state,
|
|
29
|
+
users,
|
|
30
|
+
loading: false,
|
|
31
|
+
})), on(UserActions.loadUsersFailure, (state, { error }) => ({
|
|
32
|
+
...state,
|
|
33
|
+
loading: false,
|
|
34
|
+
error,
|
|
35
|
+
})), on(UserActions.setCurrentUser, (state, { user }) => ({
|
|
36
|
+
...state,
|
|
37
|
+
currentUser: user,
|
|
38
|
+
})), on(UserActions.clearCurrentUser, state => ({
|
|
39
|
+
...state,
|
|
40
|
+
currentUser: null,
|
|
41
|
+
}))),
|
|
42
|
+
});
|
|
43
|
+
const { name: userFeatureKey, reducer: userReducer, selectUserState, selectUsers, selectCurrentUser, selectLoading, selectError, } = userFeature;
|
|
44
|
+
|
|
45
|
+
/** User feature selectors. */
|
|
2
46
|
|
|
3
47
|
/**
|
|
4
48
|
* Generated bundle index. Do not edit.
|
|
5
49
|
*/
|
|
50
|
+
|
|
51
|
+
export { UserActions, selectUsers as selectAllUsers, selectCurrentUser, selectError as selectUserError, selectLoading as selectUserLoading, selectUserState, userFeature, userFeatureKey, userReducer };
|
|
6
52
|
//# sourceMappingURL=ncim-sdk-state.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ncim-sdk-state.mjs","sources":["../../../../libs/
|
|
1
|
+
{"version":3,"file":"ncim-sdk-state.mjs","sources":["../../../../libs/shared-state/src/lib/user/user.actions.ts","../../../../libs/shared-state/src/lib/user/user.reducer.ts","../../../../libs/shared-state/src/lib/user/user.selectors.ts","../../../../libs/ncim-sdk-state.ts"],"sourcesContent":["import { createActionGroup, emptyProps, props } from '@ngrx/store';\nimport { User } from './user.model';\n\n/** User feature actions (load, set/clear current user). */\nexport const UserActions = createActionGroup({\n source: 'User',\n events: {\n 'Load Users': emptyProps(),\n 'Load Users Success': props<{ users: User[] }>(),\n 'Load Users Failure': props<{ error: string }>(),\n 'Set Current User': props<{ user: User }>(),\n 'Clear Current User': emptyProps(),\n },\n});\n","import { createFeature, createReducer, on } from '@ngrx/store';\nimport { User } from './user.model';\nimport { UserActions } from './user.actions';\n\n/** User feature state. */\nexport interface UserState {\n users: User[];\n currentUser: User | null;\n loading: boolean;\n error: string | null;\n}\n\nconst initialState: UserState = {\n users: [],\n currentUser: null,\n loading: false,\n error: null,\n};\n\nexport const userFeature = createFeature({\n name: 'user',\n reducer: createReducer(\n initialState,\n on(UserActions.loadUsers, state => ({\n ...state,\n loading: true,\n error: null,\n })),\n on(UserActions.loadUsersSuccess, (state, { users }) => ({\n ...state,\n users,\n loading: false,\n })),\n on(UserActions.loadUsersFailure, (state, { error }) => ({\n ...state,\n loading: false,\n error,\n })),\n on(UserActions.setCurrentUser, (state, { user }) => ({\n ...state,\n currentUser: user,\n })),\n on(UserActions.clearCurrentUser, state => ({\n ...state,\n currentUser: null,\n }))\n ),\n});\n\nexport const {\n name: userFeatureKey,\n reducer: userReducer,\n selectUserState,\n selectUsers,\n selectCurrentUser,\n selectLoading,\n selectError,\n} = userFeature;\n","/** User feature selectors. */\nexport {\n selectUserState,\n selectUsers as selectAllUsers,\n selectCurrentUser,\n selectLoading as selectUserLoading,\n selectError as selectUserError,\n} from './user.reducer';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './ncim-sdk-state-entry';\n"],"names":[],"mappings":";;AAGA;AACO,MAAM,WAAW,GAAG,iBAAiB,CAAC;AAC3C,IAAA,MAAM,EAAE,MAAM;AACd,IAAA,MAAM,EAAE;QACN,YAAY,EAAE,UAAU,EAAE;QAC1B,oBAAoB,EAAE,KAAK,EAAqB;QAChD,oBAAoB,EAAE,KAAK,EAAqB;QAChD,kBAAkB,EAAE,KAAK,EAAkB;QAC3C,oBAAoB,EAAE,UAAU,EAAE;AACnC,KAAA;AACF,CAAA;;ACDD,MAAM,YAAY,GAAc;AAC9B,IAAA,KAAK,EAAE,EAAE;AACT,IAAA,WAAW,EAAE,IAAI;AACjB,IAAA,OAAO,EAAE,KAAK;AACd,IAAA,KAAK,EAAE,IAAI;CACZ;AAEM,MAAM,WAAW,GAAG,aAAa,CAAC;AACvC,IAAA,IAAI,EAAE,MAAM;AACZ,IAAA,OAAO,EAAE,aAAa,CACpB,YAAY,EACZ,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,KAAK,KAAK;AAClC,QAAA,GAAG,KAAK;AACR,QAAA,OAAO,EAAE,IAAI;AACb,QAAA,KAAK,EAAE,IAAI;AACZ,KAAA,CAAC,CAAC,EACH,EAAE,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM;AACtD,QAAA,GAAG,KAAK;QACR,KAAK;AACL,QAAA,OAAO,EAAE,KAAK;AACf,KAAA,CAAC,CAAC,EACH,EAAE,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM;AACtD,QAAA,GAAG,KAAK;AACR,QAAA,OAAO,EAAE,KAAK;QACd,KAAK;AACN,KAAA,CAAC,CAAC,EACH,EAAE,CAAC,WAAW,CAAC,cAAc,EAAE,CAAC,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM;AACnD,QAAA,GAAG,KAAK;AACR,QAAA,WAAW,EAAE,IAAI;AAClB,KAAA,CAAC,CAAC,EACH,EAAE,CAAC,WAAW,CAAC,gBAAgB,EAAE,KAAK,KAAK;AACzC,QAAA,GAAG,KAAK;AACR,QAAA,WAAW,EAAE,IAAI;AAClB,KAAA,CAAC,CAAC,CACJ;AACF,CAAA;MAEY,EACX,IAAI,EAAE,cAAc,EACpB,OAAO,EAAE,WAAW,EACpB,eAAe,EACf,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,WAAW,GACZ,GAAG;;ACzDJ;;ACAA;;AAEG;;;;"}
|