@yuuvis/client-core 3.0.0-beta.21.1 → 3.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuuvis/client-core",
3
- "version": "3.0.0-beta.21.1",
3
+ "version": "3.0.0",
4
4
  "author": "OPTIMAL SYSTEMS GmbH <npm@optimal-systems.de>",
5
5
  "license": "MIT",
6
6
  "peerDependencies": {
@@ -317,60 +317,132 @@ declare class YuvError implements Error {
317
317
  }
318
318
 
319
319
  /**
320
- * Represents an entry in the organization set, which can be either a user or a role.
321
- * Used in search results and organization entity queries.
320
+ * Represents an entity in the organization set either a user or a role.
321
+ *
322
+ * This is the unified result type returned by {@link IdmService.queryOrganizationEntity}.
323
+ * It normalizes both user and role search results into a common shape so consumers
324
+ * (autocomplete fields, assignment dialogs, permission pickers) can treat them uniformly.
325
+ *
326
+ * **Mapping from backend:**
327
+ * ```
328
+ * User → { id: user.id, title: "Lastname, Firstname (username)", type: 'user' }
329
+ * Role → { id: role.name, title: role.name, type: 'role' }
330
+ * ```
331
+ *
332
+ * **Usage:**
333
+ * Typically used in autocomplete/search components where a user can assign
334
+ * a document or task to either a person or a role:
335
+ * ```ts
336
+ * idmService.queryOrganizationEntity('admin', ['user', 'role'])
337
+ * .subscribe((entries: OrganizationSetEntry[]) => {
338
+ * // entries contains both matching users and roles
339
+ * });
340
+ * ```
341
+ *
342
+ * @see {@link IdmService.queryOrganizationEntity} for the search method
322
343
  */
323
344
  interface OrganizationSetEntry {
324
- /** The unique identifier of the user or role */
345
+ /** Unique identifier user UUID for users, role name for roles */
325
346
  id: string;
326
- /** The display title/name for the entry */
347
+ /** Human-readable display title for the entity */
327
348
  title: string;
328
- /** The type of organization entity */
349
+ /** Discriminator indicating whether this entry is a user or a role */
329
350
  type: 'user' | 'role';
330
351
  }
331
352
 
332
353
  /**
333
- * Represents the user data structure returned from the IDM API.
334
- * Contains all essential user information including authentication and authorization details.
354
+ * Represents the user data structure returned from the IDM backend API (`/idm/users/{id}`).
355
+ *
356
+ * This is the raw transport interface — it maps 1:1 to the JSON payload from the identity
357
+ * management service. The application-level model {@link YuvUser} wraps this interface and
358
+ * adds computed properties (display name, locale, settings).
359
+ *
360
+ * **Typical Flow:**
361
+ * ```
362
+ * Backend API ──► IdmUserResponse (raw JSON) ──► YuvUser (app model)
363
+ * ```
364
+ *
365
+ * **Usage:**
366
+ * - Consumed internally by {@link IdmService.getUserById} to type the HTTP response
367
+ * - Passed into the {@link YuvUser} constructor for hydration
368
+ * - Stored in {@link IdmCachedUser} for persistence in the client cache
369
+ *
370
+ * @see {@link IdmService.getUserById} for the fetching and caching logic
371
+ * @see {@link YuvUser} for the application-level user model
335
372
  */
336
373
  interface IdmUserResponse {
337
- /** The unique username for login */
374
+ /** Unique username used for login / authentication */
338
375
  username: string;
339
- /** The unique user identifier */
376
+ /** Unique, immutable user identifier (UUID) */
340
377
  id: string;
341
- /** The user's email address */
378
+ /** User's email address */
342
379
  email: string;
343
- /** The user's first name */
380
+ /** User's first name */
344
381
  firstname: string;
345
- /** The user's last name */
382
+ /** User's last name */
346
383
  lastname: string;
347
- /** Whether the user account is enabled/active */
384
+ /** Whether the user account is currently enabled and active */
348
385
  enabled: boolean;
349
- /** The tenant identifier this user belongs to */
386
+ /** Tenant identifier this user belongs to (multi-tenancy discriminator) */
350
387
  tenant: string;
351
- /** Array of granted authorities/permissions for the user */
388
+ /** Granted authorities / permission roles assigned to the user */
352
389
  authorities: string[];
353
- /** The formatted display name for the user */
390
+ /** Pre-formatted display name from the backend (e.g. "Lastname, Firstname (username)") */
354
391
  displayName: string;
355
392
  }
356
393
 
357
394
  /**
358
- * Represents a cached user entry with expiration timestamp.
359
- * Used internally by IdmService to manage user data caching.
395
+ * Represents a single cached user entry with an expiration timestamp.
396
+ *
397
+ * Used internally by {@link IdmService} to wrap raw {@link IdmUserResponse} data
398
+ * with a TTL-based expiry. When `Date.now()` exceeds {@link expires}, the entry
399
+ * is considered stale and the service re-fetches from the backend.
400
+ *
401
+ * **Cache Lifecycle:**
402
+ * ```
403
+ * [User fetched] ──► IdmCachedUser created ──► stored in IdmUserCache
404
+ * (expires = now + 1h)
405
+ *
406
+ * [Next access]
407
+ * ├─ Date.now() < expires → return from cache (no HTTP call)
408
+ * └─ Date.now() ≥ expires → re-fetch from backend, update cache
409
+ * ```
410
+ *
411
+ * @see {@link IdmUserCache} for the dictionary that holds these entries
412
+ * @see {@link IdmService.getUserById} for the caching logic
360
413
  */
361
414
  interface IdmCachedUser {
362
- /** Timestamp when the cache expires (Date.now() + TTL) */
415
+ /** Unix timestamp (ms) when this cache entry expires (`Date.now() + TTL`) */
363
416
  expires: number;
364
- /** The cached user data from the IDM API */
417
+ /** Raw user data from the IDM backend API */
365
418
  user: IdmUserResponse;
366
419
  }
367
420
 
368
421
  /**
369
- * Dictionary/map structure for storing cached user data.
370
- * Keys are user IDs and values are cached user entries with expiration.
422
+ * Dictionary structure for the in-memory and persisted IDM user cache.
423
+ *
424
+ * Maps user IDs (UUIDs) to their {@link IdmCachedUser} entries. The entire map
425
+ * is persisted as a single blob in {@link ClientCacheService} under the key
426
+ * `yuv-idm-user-cache`, so all cached users are loaded/saved atomically.
427
+ *
428
+ * **Storage Strategy:**
429
+ * ```
430
+ * ClientCacheService (IndexedDB / localStorage)
431
+ * └─ "yuv-idm-user-cache" → IdmUserCache
432
+ * ├─ "user-uuid-1" → { expires: ..., user: { ... } }
433
+ * ├─ "user-uuid-2" → { expires: ..., user: { ... } }
434
+ * └─ "user-uuid-N" → { expires: ..., user: { ... } }
435
+ * ```
436
+ *
437
+ * **Why a single map instead of per-user cache entries:**
438
+ * - Atomic load on startup — one read populates the entire in-memory cache
439
+ * - Avoids N+1 storage reads when resolving multiple users (e.g. audit trails, comment threads)
440
+ * - Per-entry TTL is still enforced via {@link IdmCachedUser.expires}
441
+ *
442
+ * @see {@link IdmCachedUser} for the per-user entry structure
443
+ * @see {@link IdmService} for the cache management logic
371
444
  */
372
445
  interface IdmUserCache {
373
- /** Map of user IDs to their cached user data */
374
446
  [userId: string]: IdmCachedUser;
375
447
  }
376
448
 
@@ -1481,39 +1553,131 @@ type YuvEventUpdatedData = DmsObject;
1481
1553
  type YuvEventCreatedData = string[];
1482
1554
 
1483
1555
  /**
1484
- * Service for managing Identity Management (IDM) operations.
1485
- * Provides functionality for querying users, roles, and organization entities,
1486
- * with built-in caching mechanisms to optimize performance.
1556
+ * Centralized service for Identity Management (IDM) operations.
1557
+ *
1558
+ * Provides a typed API for querying users, roles, and organization entities
1559
+ * from the IDM backend, with a built-in client-side caching layer that
1560
+ * minimizes redundant HTTP calls.
1561
+ *
1562
+ * **Key Features:**
1563
+ * - User lookup by ID with automatic 1-hour TTL cache
1564
+ * - Unified search across users and roles via a single method
1565
+ * - Role listing with optional name filter
1566
+ * - Cache persisted to IndexedDB/localStorage (survives page refresh)
1567
+ * - In-memory cache hydrated on service creation for instant access
1568
+ *
1569
+ * **Caching Strategy:**
1570
+ * All cached users are stored as a single map ({@link IdmUserCache}) under one
1571
+ * storage key. This enables atomic load on startup — one read populates the
1572
+ * entire in-memory cache — and avoids N+1 reads when resolving multiple users
1573
+ * (e.g. audit trails, comment threads, assignment lists). Per-entry TTL is
1574
+ * enforced via {@link IdmCachedUser.expires}.
1575
+ *
1576
+ * ```
1577
+ * getUserById("abc")
1578
+ * ├─ Cache hit & valid → return immediately (no HTTP)
1579
+ * └─ Cache miss/expired → GET /idm/users/abc
1580
+ * ├─ Update in-memory cache
1581
+ * ├─ Persist to ClientCacheService
1582
+ * └─ Return YuvUser
1583
+ * ```
1584
+ *
1585
+ * **API Endpoints:**
1586
+ * | Method | Endpoint |
1587
+ * |----------------------------|----------------------|
1588
+ * | `queryOrganizationEntity` | `GET /idm/search` |
1589
+ * | `getRoles` | `GET /idm/roles` |
1590
+ * | `getUserById` | `GET /idm/users/:id` |
1591
+ *
1592
+ * **Usage:**
1593
+ * ```ts
1594
+ * const idm = inject(IdmService);
1595
+ *
1596
+ * // Search users and roles
1597
+ * idm.queryOrganizationEntity('admin', ['user', 'role'])
1598
+ * .subscribe(entries => console.log(entries));
1599
+ *
1600
+ * // Get a user by ID (cached)
1601
+ * idm.getUserById('user-uuid').subscribe(user => console.log(user?.title));
1602
+ *
1603
+ * // List roles
1604
+ * idm.getRoles('ADMIN').subscribe(roles => console.log(roles));
1605
+ * ```
1606
+ *
1607
+ * @see {@link ClientCacheService} for the underlying persistence layer
1608
+ * @see {@link YuvUser} for the application-level user model
1487
1609
  */
1488
1610
  declare class IdmService {
1489
1611
  #private;
1490
- userCache: IdmUserCache;
1491
1612
  constructor();
1492
1613
  /**
1493
- * Queries organization entities (users and/or roles) based on search term.
1614
+ * Searches organization entities (users and/or roles) by a free-text term.
1615
+ *
1616
+ * Returns a unified {@link OrganizationSetEntry} array so consumers
1617
+ * (autocomplete fields, assignment dialogs, permission pickers) can
1618
+ * treat users and roles interchangeably.
1494
1619
  *
1495
- * @param term - The search term to filter entities
1496
- * @param targetTypes - Array of entity types to search for ('user', 'role')
1620
+ * @param term - Free-text search term to filter entities
1621
+ * @param targetTypes - Entity types to include in results (`'user'`, `'role'`, or both)
1497
1622
  * @param size - Optional maximum number of results to return
1498
- * @returns Observable array of organization set entries matching the search criteria
1623
+ * @returns Observable of matching organization entities
1624
+ *
1625
+ * @example
1626
+ * ```ts
1627
+ * // Search for users and roles matching "admin"
1628
+ * idmService.queryOrganizationEntity('admin', ['user', 'role'], 10)
1629
+ * .subscribe(entries => {
1630
+ * const users = entries.filter(e => e.type === 'user');
1631
+ * const roles = entries.filter(e => e.type === 'role');
1632
+ * });
1633
+ * ```
1499
1634
  */
1500
1635
  queryOrganizationEntity(term: string, targetTypes: string[], size?: number): Observable<OrganizationSetEntry[]>;
1501
1636
  /**
1502
1637
  * Retrieves available roles, optionally filtered by a search term.
1503
1638
  *
1639
+ * Returns an empty array on error to ensure consumers can always
1640
+ * safely iterate the result without null-checking.
1641
+ *
1504
1642
  * @param role - Optional search term to filter roles by name
1505
- * @returns Observable array of role objects containing name and description
1643
+ * @returns Observable of role objects containing name and description
1644
+ *
1645
+ * @example
1646
+ * ```ts
1647
+ * // List all roles
1648
+ * idmService.getRoles().subscribe(roles => console.log(roles));
1649
+ *
1650
+ * // Filter roles by name
1651
+ * idmService.getRoles('ADMIN').subscribe(roles => console.log(roles));
1652
+ * ```
1506
1653
  */
1507
1654
  getRoles(role?: string): Observable<{
1508
1655
  name: string;
1509
1656
  description: string;
1510
1657
  }[]>;
1511
1658
  /**
1512
- * Retrieves user information by user ID with automatic caching.
1513
- * Uses a 1-hour TTL cache to minimize backend requests.
1659
+ * Retrieves a user by ID with automatic caching.
1660
+ *
1661
+ * Checks the in-memory cache first. If a valid (non-expired) entry exists,
1662
+ * it is returned immediately without an HTTP call. Otherwise, the user is
1663
+ * fetched from the backend, stored in both the in-memory and persistent
1664
+ * cache, and returned as a {@link YuvUser}.
1665
+ *
1666
+ * Returns `null` if the user is not found or the request fails,
1667
+ * so consumers can safely use the result without try/catch.
1514
1668
  *
1515
- * @param id - The unique identifier of the user
1516
- * @returns Observable of YuvUser object or null if user is not found
1669
+ * @param id - Unique user identifier (UUID)
1670
+ * @returns Observable of the user model, or `null` if not found / on error
1671
+ *
1672
+ * @example
1673
+ * ```ts
1674
+ * idmService.getUserById('550e8400-e29b-41d4-a716-446655440000')
1675
+ * .subscribe(user => {
1676
+ * if (user) {
1677
+ * console.log(user.getFullName());
1678
+ * }
1679
+ * });
1680
+ * ```
1517
1681
  */
1518
1682
  getUserById(id: string): Observable<YuvUser | null>;
1519
1683
  static ɵfac: i0.ɵɵFactoryDeclaration<IdmService, never>;