@yuuvis/client-core 2.20.0 → 2.21.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.
@@ -35,7 +35,7 @@ export declare class AuthService {
35
35
  * redirect the user to the requested page after authentication.
36
36
  * This is done on app initialization (core-init).
37
37
  */
38
- setInitialRequestUri(): void;
38
+ setInitialRequestUri(): Observable<boolean>;
39
39
  /**
40
40
  * Get the URL that entered the app. May be a deep link that could then be
41
41
  * picked up again after user has been authenticated.
@@ -2,4 +2,4 @@ import { YuvConfig } from '../config/config.interface';
2
2
  /**
3
3
  * Providing functions,that are are injected at application startup and executed during app initialization.
4
4
  */
5
- export declare const init_moduleFnc: () => import("rxjs").Observable<YuvConfig[]> | import("rxjs").Observable<boolean | import("@yuuvis/client-core").YuvUser>;
5
+ export declare const init_moduleFnc: () => import("rxjs").Observable<boolean | import("@yuuvis/client-core").YuvUser | YuvConfig[]>;
@@ -1,41 +1,133 @@
1
1
  import { Observable } from 'rxjs';
2
2
  import { YuvUser } from '../../model/yuv-user.model';
3
- import { IdmUserCache, OrganizationSetEntry } from './models';
3
+ import { OrganizationSetEntry } from './models';
4
4
  import * as i0 from "@angular/core";
5
5
  /**
6
- * Service for managing Identity Management (IDM) operations.
7
- * Provides functionality for querying users, roles, and organization entities,
8
- * with built-in caching mechanisms to optimize performance.
6
+ * Centralized service for Identity Management (IDM) operations.
7
+ *
8
+ * Provides a typed API for querying users, roles, and organization entities
9
+ * from the IDM backend, with a built-in client-side caching layer that
10
+ * minimizes redundant HTTP calls.
11
+ *
12
+ * **Key Features:**
13
+ * - User lookup by ID with automatic 1-hour TTL cache
14
+ * - Unified search across users and roles via a single method
15
+ * - Role listing with optional name filter
16
+ * - Cache persisted to IndexedDB/localStorage (survives page refresh)
17
+ * - In-memory cache hydrated on service creation for instant access
18
+ *
19
+ * **Caching Strategy:**
20
+ * All cached users are stored as a single map ({@link IdmUserCache}) under one
21
+ * storage key. This enables atomic load on startup — one read populates the
22
+ * entire in-memory cache — and avoids N+1 reads when resolving multiple users
23
+ * (e.g. audit trails, comment threads, assignment lists). Per-entry TTL is
24
+ * enforced via {@link IdmCachedUser.expires}.
25
+ *
26
+ * ```
27
+ * getUserById("abc")
28
+ * ├─ Cache hit & valid → return immediately (no HTTP)
29
+ * └─ Cache miss/expired → GET /idm/users/abc
30
+ * ├─ Update in-memory cache
31
+ * ├─ Persist to ClientCacheService
32
+ * └─ Return YuvUser
33
+ * ```
34
+ *
35
+ * **API Endpoints:**
36
+ * | Method | Endpoint |
37
+ * |----------------------------|----------------------|
38
+ * | `queryOrganizationEntity` | `GET /idm/search` |
39
+ * | `getRoles` | `GET /idm/roles` |
40
+ * | `getUserById` | `GET /idm/users/:id` |
41
+ *
42
+ * **Usage:**
43
+ * ```ts
44
+ * const idm = inject(IdmService);
45
+ *
46
+ * // Search users and roles
47
+ * idm.queryOrganizationEntity('admin', ['user', 'role'])
48
+ * .subscribe(entries => console.log(entries));
49
+ *
50
+ * // Get a user by ID (cached)
51
+ * idm.getUserById('user-uuid').subscribe(user => console.log(user?.title));
52
+ *
53
+ * // List roles
54
+ * idm.getRoles('ADMIN').subscribe(roles => console.log(roles));
55
+ * ```
56
+ *
57
+ * @see {@link ClientCacheService} for the underlying persistence layer
58
+ * @see {@link YuvUser} for the application-level user model
9
59
  */
10
60
  export declare class IdmService {
11
61
  #private;
12
- userCache: IdmUserCache;
13
62
  constructor();
14
63
  /**
15
- * Queries organization entities (users and/or roles) based on search term.
64
+ * Searches organization entities (users and/or roles) by a free-text term.
16
65
  *
17
- * @param term - The search term to filter entities
18
- * @param targetTypes - Array of entity types to search for ('user', 'role')
66
+ * Returns a unified {@link OrganizationSetEntry} array so consumers
67
+ * (autocomplete fields, assignment dialogs, permission pickers) can
68
+ * treat users and roles interchangeably.
69
+ *
70
+ * @param term - Free-text search term to filter entities
71
+ * @param targetTypes - Entity types to include in results (`'user'`, `'role'`, or both)
19
72
  * @param size - Optional maximum number of results to return
20
- * @returns Observable array of organization set entries matching the search criteria
73
+ * @returns Observable of matching organization entities
74
+ *
75
+ * @example
76
+ * ```ts
77
+ * // Search for users and roles matching "admin"
78
+ * idmService.queryOrganizationEntity('admin', ['user', 'role'], 10)
79
+ * .subscribe(entries => {
80
+ * const users = entries.filter(e => e.type === 'user');
81
+ * const roles = entries.filter(e => e.type === 'role');
82
+ * });
83
+ * ```
21
84
  */
22
85
  queryOrganizationEntity(term: string, targetTypes: string[], size?: number): Observable<OrganizationSetEntry[]>;
23
86
  /**
24
87
  * Retrieves available roles, optionally filtered by a search term.
25
88
  *
89
+ * Returns an empty array on error to ensure consumers can always
90
+ * safely iterate the result without null-checking.
91
+ *
26
92
  * @param role - Optional search term to filter roles by name
27
- * @returns Observable array of role objects containing name and description
93
+ * @returns Observable of role objects containing name and description
94
+ *
95
+ * @example
96
+ * ```ts
97
+ * // List all roles
98
+ * idmService.getRoles().subscribe(roles => console.log(roles));
99
+ *
100
+ * // Filter roles by name
101
+ * idmService.getRoles('ADMIN').subscribe(roles => console.log(roles));
102
+ * ```
28
103
  */
29
104
  getRoles(role?: string): Observable<{
30
105
  name: string;
31
106
  description: string;
32
107
  }[]>;
33
108
  /**
34
- * Retrieves user information by user ID with automatic caching.
35
- * Uses a 1-hour TTL cache to minimize backend requests.
109
+ * Retrieves a user by ID with automatic caching.
110
+ *
111
+ * Checks the in-memory cache first. If a valid (non-expired) entry exists,
112
+ * it is returned immediately without an HTTP call. Otherwise, the user is
113
+ * fetched from the backend, stored in both the in-memory and persistent
114
+ * cache, and returned as a {@link YuvUser}.
115
+ *
116
+ * Returns `null` if the user is not found or the request fails,
117
+ * so consumers can safely use the result without try/catch.
118
+ *
119
+ * @param id - Unique user identifier (UUID)
120
+ * @returns Observable of the user model, or `null` if not found / on error
36
121
  *
37
- * @param id - The unique identifier of the user
38
- * @returns Observable of YuvUser object or null if user is not found
122
+ * @example
123
+ * ```ts
124
+ * idmService.getUserById('550e8400-e29b-41d4-a716-446655440000')
125
+ * .subscribe(user => {
126
+ * if (user) {
127
+ * console.log(user.getFullName());
128
+ * }
129
+ * });
130
+ * ```
39
131
  */
40
132
  getUserById(id: string): Observable<YuvUser | null>;
41
133
  static ɵfac: i0.ɵɵFactoryDeclaration<IdmService, never>;
@@ -1,11 +1,27 @@
1
1
  import { IdmUserResponse } from './idm-user-response.model';
2
2
  /**
3
- * Represents a cached user entry with expiration timestamp.
4
- * Used internally by IdmService to manage user data caching.
3
+ * Represents a single cached user entry with an expiration timestamp.
4
+ *
5
+ * Used internally by {@link IdmService} to wrap raw {@link IdmUserResponse} data
6
+ * with a TTL-based expiry. When `Date.now()` exceeds {@link expires}, the entry
7
+ * is considered stale and the service re-fetches from the backend.
8
+ *
9
+ * **Cache Lifecycle:**
10
+ * ```
11
+ * [User fetched] ──► IdmCachedUser created ──► stored in IdmUserCache
12
+ * (expires = now + 1h)
13
+ *
14
+ * [Next access]
15
+ * ├─ Date.now() < expires → return from cache (no HTTP call)
16
+ * └─ Date.now() ≥ expires → re-fetch from backend, update cache
17
+ * ```
18
+ *
19
+ * @see {@link IdmUserCache} for the dictionary that holds these entries
20
+ * @see {@link IdmService.getUserById} for the caching logic
5
21
  */
6
22
  export interface IdmCachedUser {
7
- /** Timestamp when the cache expires (Date.now() + TTL) */
23
+ /** Unix timestamp (ms) when this cache entry expires (`Date.now() + TTL`) */
8
24
  expires: number;
9
- /** The cached user data from the IDM API */
25
+ /** Raw user data from the IDM backend API */
10
26
  user: IdmUserResponse;
11
27
  }
@@ -1,9 +1,28 @@
1
1
  import { IdmCachedUser } from './idm-cached-user.model';
2
2
  /**
3
- * Dictionary/map structure for storing cached user data.
4
- * Keys are user IDs and values are cached user entries with expiration.
3
+ * Dictionary structure for the in-memory and persisted IDM user cache.
4
+ *
5
+ * Maps user IDs (UUIDs) to their {@link IdmCachedUser} entries. The entire map
6
+ * is persisted as a single blob in {@link ClientCacheService} under the key
7
+ * `yuv-idm-user-cache`, so all cached users are loaded/saved atomically.
8
+ *
9
+ * **Storage Strategy:**
10
+ * ```
11
+ * ClientCacheService (IndexedDB / localStorage)
12
+ * └─ "yuv-idm-user-cache" → IdmUserCache
13
+ * ├─ "user-uuid-1" → { expires: ..., user: { ... } }
14
+ * ├─ "user-uuid-2" → { expires: ..., user: { ... } }
15
+ * └─ "user-uuid-N" → { expires: ..., user: { ... } }
16
+ * ```
17
+ *
18
+ * **Why a single map instead of per-user cache entries:**
19
+ * - Atomic load on startup — one read populates the entire in-memory cache
20
+ * - Avoids N+1 storage reads when resolving multiple users (e.g. audit trails, comment threads)
21
+ * - Per-entry TTL is still enforced via {@link IdmCachedUser.expires}
22
+ *
23
+ * @see {@link IdmCachedUser} for the per-user entry structure
24
+ * @see {@link IdmService} for the cache management logic
5
25
  */
6
26
  export interface IdmUserCache {
7
- /** Map of user IDs to their cached user data */
8
27
  [userId: string]: IdmCachedUser;
9
28
  }
@@ -1,24 +1,40 @@
1
1
  /**
2
- * Represents the user data structure returned from the IDM API.
3
- * Contains all essential user information including authentication and authorization details.
2
+ * Represents the user data structure returned from the IDM backend API (`/idm/users/{id}`).
3
+ *
4
+ * This is the raw transport interface — it maps 1:1 to the JSON payload from the identity
5
+ * management service. The application-level model {@link YuvUser} wraps this interface and
6
+ * adds computed properties (display name, locale, settings).
7
+ *
8
+ * **Typical Flow:**
9
+ * ```
10
+ * Backend API ──► IdmUserResponse (raw JSON) ──► YuvUser (app model)
11
+ * ```
12
+ *
13
+ * **Usage:**
14
+ * - Consumed internally by {@link IdmService.getUserById} to type the HTTP response
15
+ * - Passed into the {@link YuvUser} constructor for hydration
16
+ * - Stored in {@link IdmCachedUser} for persistence in the client cache
17
+ *
18
+ * @see {@link IdmService.getUserById} for the fetching and caching logic
19
+ * @see {@link YuvUser} for the application-level user model
4
20
  */
5
21
  export interface IdmUserResponse {
6
- /** The unique username for login */
22
+ /** Unique username used for login / authentication */
7
23
  username: string;
8
- /** The unique user identifier */
24
+ /** Unique, immutable user identifier (UUID) */
9
25
  id: string;
10
- /** The user's email address */
26
+ /** User's email address */
11
27
  email: string;
12
- /** The user's first name */
28
+ /** User's first name */
13
29
  firstname: string;
14
- /** The user's last name */
30
+ /** User's last name */
15
31
  lastname: string;
16
- /** Whether the user account is enabled/active */
32
+ /** Whether the user account is currently enabled and active */
17
33
  enabled: boolean;
18
- /** The tenant identifier this user belongs to */
34
+ /** Tenant identifier this user belongs to (multi-tenancy discriminator) */
19
35
  tenant: string;
20
- /** Array of granted authorities/permissions for the user */
36
+ /** Granted authorities / permission roles assigned to the user */
21
37
  authorities: string[];
22
- /** The formatted display name for the user */
38
+ /** Pre-formatted display name from the backend (e.g. "Lastname, Firstname (username)") */
23
39
  displayName: string;
24
40
  }
@@ -1,12 +1,33 @@
1
1
  /**
2
- * Represents an entry in the organization set, which can be either a user or a role.
3
- * Used in search results and organization entity queries.
2
+ * Represents an entity in the organization set either a user or a role.
3
+ *
4
+ * This is the unified result type returned by {@link IdmService.queryOrganizationEntity}.
5
+ * It normalizes both user and role search results into a common shape so consumers
6
+ * (autocomplete fields, assignment dialogs, permission pickers) can treat them uniformly.
7
+ *
8
+ * **Mapping from backend:**
9
+ * ```
10
+ * User → { id: user.id, title: "Lastname, Firstname (username)", type: 'user' }
11
+ * Role → { id: role.name, title: role.name, type: 'role' }
12
+ * ```
13
+ *
14
+ * **Usage:**
15
+ * Typically used in autocomplete/search components where a user can assign
16
+ * a document or task to either a person or a role:
17
+ * ```ts
18
+ * idmService.queryOrganizationEntity('admin', ['user', 'role'])
19
+ * .subscribe((entries: OrganizationSetEntry[]) => {
20
+ * // entries contains both matching users and roles
21
+ * });
22
+ * ```
23
+ *
24
+ * @see {@link IdmService.queryOrganizationEntity} for the search method
4
25
  */
5
26
  export interface OrganizationSetEntry {
6
- /** The unique identifier of the user or role */
27
+ /** Unique identifier user UUID for users, role name for roles */
7
28
  id: string;
8
- /** The display title/name for the entry */
29
+ /** Human-readable display title for the entity */
9
30
  title: string;
10
- /** The type of organization entity */
31
+ /** Discriminator indicating whether this entry is a user or a role */
11
32
  type: 'user' | 'role';
12
33
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuuvis/client-core",
3
- "version": "2.20.0",
3
+ "version": "2.21.0",
4
4
  "author": "OPTIMAL SYSTEMS GmbH <npm@optimal-systems.de>",
5
5
  "license": "MIT",
6
6
  "peerDependencies": {