@yuuvis/client-core 3.0.0-beta.21.2 → 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
|
@@ -317,60 +317,132 @@ declare class YuvError implements Error {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
/**
|
|
320
|
-
* Represents an
|
|
321
|
-
*
|
|
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
|
-
/**
|
|
345
|
+
/** Unique identifier — user UUID for users, role name for roles */
|
|
325
346
|
id: string;
|
|
326
|
-
/**
|
|
347
|
+
/** Human-readable display title for the entity */
|
|
327
348
|
title: string;
|
|
328
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
374
|
+
/** Unique username used for login / authentication */
|
|
338
375
|
username: string;
|
|
339
|
-
/**
|
|
376
|
+
/** Unique, immutable user identifier (UUID) */
|
|
340
377
|
id: string;
|
|
341
|
-
/**
|
|
378
|
+
/** User's email address */
|
|
342
379
|
email: string;
|
|
343
|
-
/**
|
|
380
|
+
/** User's first name */
|
|
344
381
|
firstname: string;
|
|
345
|
-
/**
|
|
382
|
+
/** User's last name */
|
|
346
383
|
lastname: string;
|
|
347
|
-
/** Whether the user account is enabled
|
|
384
|
+
/** Whether the user account is currently enabled and active */
|
|
348
385
|
enabled: boolean;
|
|
349
|
-
/**
|
|
386
|
+
/** Tenant identifier this user belongs to (multi-tenancy discriminator) */
|
|
350
387
|
tenant: string;
|
|
351
|
-
/**
|
|
388
|
+
/** Granted authorities / permission roles assigned to the user */
|
|
352
389
|
authorities: string[];
|
|
353
|
-
/**
|
|
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
|
-
*
|
|
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
|
-
/**
|
|
415
|
+
/** Unix timestamp (ms) when this cache entry expires (`Date.now() + TTL`) */
|
|
363
416
|
expires: number;
|
|
364
|
-
/**
|
|
417
|
+
/** Raw user data from the IDM backend API */
|
|
365
418
|
user: IdmUserResponse;
|
|
366
419
|
}
|
|
367
420
|
|
|
368
421
|
/**
|
|
369
|
-
* Dictionary
|
|
370
|
-
*
|
|
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
|
-
*
|
|
1485
|
-
*
|
|
1486
|
-
*
|
|
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
|
-
*
|
|
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 -
|
|
1496
|
-
* @param targetTypes -
|
|
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
|
|
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
|
|
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
|
|
1513
|
-
*
|
|
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 -
|
|
1516
|
-
* @returns Observable of
|
|
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>;
|