@masterteam/delegations 0.0.55 → 0.0.57

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": "@masterteam/delegations",
3
- "version": "0.0.55",
3
+ "version": "0.0.57",
4
4
  "publishConfig": {
5
5
  "directory": "../../../dist/masterteam/delegations",
6
6
  "linkDirectory": false,
@@ -20,9 +20,9 @@
20
20
  "tailwindcss": "^4.2.2",
21
21
  "tailwindcss-primeui": "^0.6.1",
22
22
  "@ngxs/store": "^20.1.0",
23
- "@masterteam/forms": "^0.0.136",
23
+ "@masterteam/components": "^0.0.271",
24
24
  "@masterteam/icons": "^0.0.17",
25
- "@masterteam/components": "^0.0.271"
25
+ "@masterteam/forms": "^0.0.136"
26
26
  },
27
27
  "sideEffects": false,
28
28
  "exports": {
@@ -421,16 +421,24 @@ declare class TopbarDelegationMenu implements OnInit {
421
421
  * e.g. embedded in the user-avatar dropdown via {@link DelegationMenuPanel}.
422
422
  */
423
423
  readonly headless: _angular_core.InputSignal<boolean>;
424
+ /**
425
+ * Optional richer profile for the "you" row of the switcher. Forwarded to
426
+ * {@link DelegationMenuPanel}; omit it and the current user is derived from
427
+ * the assigned delegation rows.
428
+ */
429
+ readonly currentUser: _angular_core.InputSignal<DelegationParty | null>;
424
430
  private readonly facade;
425
431
  private readonly modal;
426
432
  private readonly transloco;
427
433
  private readonly destroyRef;
434
+ private readonly actions$;
435
+ private readonly toast;
428
436
  protected readonly popover: _angular_core.Signal<Popover | undefined>;
429
437
  protected readonly active: _angular_core.Signal<_masterteam_delegations.ActiveDelegationSession | null>;
430
438
  protected readonly candidates: _angular_core.Signal<DelegationRow[]>;
431
439
  protected readonly hasCandidates: _angular_core.Signal<boolean>;
432
- protected readonly onBehalfOf: _angular_core.Signal<_masterteam_delegations.DelegationParty | null>;
433
- protected readonly executedBy: _angular_core.Signal<_masterteam_delegations.DelegationParty | null>;
440
+ protected readonly onBehalfOf: _angular_core.Signal<DelegationParty | null>;
441
+ protected readonly executedBy: _angular_core.Signal<DelegationParty>;
434
442
  protected readonly popoverOpen: _angular_core.WritableSignal<boolean>;
435
443
  private promptPending;
436
444
  private promptRefreshQueued;
@@ -443,7 +451,7 @@ declare class TopbarDelegationMenu implements OnInit {
443
451
  * "act on behalf of" dialog over the login page.
444
452
  */
445
453
  private promptRefs;
446
- protected readonly mode: _angular_core.Signal<"candidates" | "active" | "hidden">;
454
+ protected readonly mode: _angular_core.Signal<"active" | "candidates" | "hidden">;
447
455
  constructor();
448
456
  ngOnInit(): void;
449
457
  /** Two-letter initials for a delegator avatar (matches the user-menu pattern). */
@@ -458,16 +466,30 @@ declare class TopbarDelegationMenu implements OnInit {
458
466
  private closePromptFlow;
459
467
  private finishPromptFlow;
460
468
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<TopbarDelegationMenu, never>;
461
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<TopbarDelegationMenu, "mt-topbar-delegation-menu", never, { "managePath": { "alias": "managePath"; "required": false; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; "showManageLink": { "alias": "showManageLink"; "required": false; "isSignal": true; }; "promptOnCandidates": { "alias": "promptOnCandidates"; "required": false; "isSignal": true; }; "headless": { "alias": "headless"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
469
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<TopbarDelegationMenu, "mt-topbar-delegation-menu", never, { "managePath": { "alias": "managePath"; "required": false; "isSignal": true; }; "compact": { "alias": "compact"; "required": false; "isSignal": true; }; "showManageLink": { "alias": "showManageLink"; "required": false; "isSignal": true; }; "promptOnCandidates": { "alias": "promptOnCandidates"; "required": false; "isSignal": true; }; "headless": { "alias": "headless"; "required": false; "isSignal": true; }; "currentUser": { "alias": "currentUser"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
462
470
  }
463
471
 
472
+ /** One selectable identity in the switcher. */
473
+ interface DelegationIdentityOption {
474
+ /** `null` for the real signed-in user; the delegation row otherwise. */
475
+ row: DelegationRow | null;
476
+ party: DelegationParty | null;
477
+ isSelf: boolean;
478
+ isActive: boolean;
479
+ initials: string;
480
+ }
464
481
  /**
465
- * Embeddable delegation menu content (doc 05, 09): renders the candidate /
466
- * active-session rows and the start / switch / end actions, with no trigger of
467
- * its own. Designed to be dropped inside a host menu (e.g. the user-avatar
468
- * dropdown) or the topbar popover. Reads the shared `DelegationSessionFacade`
469
- * signals; candidate loading + the post-login prompt stay in the always-mounted
470
- * `TopbarDelegationMenu` controller.
482
+ * Embeddable "acting as" account switcher (doc 05, 09).
483
+ *
484
+ * Renders one row per identity the user can operate as themselves first, then
485
+ * every delegator who has an active delegation assigned to them — with the
486
+ * current one checked. Picking a row starts, switches, or ends the delegated
487
+ * session; the {@link StartSessionDialog} still takes explicit consent before
488
+ * any session begins, so this list never changes authority on its own.
489
+ *
490
+ * Designed to be dropped inside a host menu (e.g. the user-avatar dropdown) or
491
+ * the topbar popover. Candidate loading + the post-login prompt stay in the
492
+ * always-mounted `TopbarDelegationMenu` controller.
471
493
  *
472
494
  * Emits `closeRequested` after any action so the host overlay can dismiss.
473
495
  */
@@ -475,28 +497,37 @@ declare class DelegationMenuPanel {
475
497
  /** Path to the management page, e.g. `/control-panel/delegations` or `/delegations`. */
476
498
  readonly managePath: _angular_core.InputSignal<string>;
477
499
  readonly showManageLink: _angular_core.InputSignal<boolean>;
500
+ /**
501
+ * Optional richer profile for the "you" row. Falls back to the current user
502
+ * carried on the assigned delegation rows, so the host may omit it.
503
+ */
504
+ readonly currentUser: _angular_core.InputSignal<DelegationParty | null>;
478
505
  readonly closeRequested: _angular_core.OutputEmitterRef<void>;
479
506
  private readonly facade;
480
507
  private readonly modal;
481
508
  private readonly transloco;
509
+ private readonly toast;
482
510
  protected readonly active: _angular_core.Signal<_masterteam_delegations.ActiveDelegationSession | null>;
483
511
  protected readonly candidates: _angular_core.Signal<DelegationRow[]>;
484
512
  protected readonly hasCandidates: _angular_core.Signal<boolean>;
485
513
  protected readonly hasMoreCandidates: _angular_core.Signal<boolean>;
486
514
  protected readonly isLoadingCandidates: _angular_core.Signal<boolean>;
487
- protected readonly onBehalfOf: _angular_core.Signal<_masterteam_delegations.DelegationParty | null>;
488
- protected readonly executedBy: _angular_core.Signal<_masterteam_delegations.DelegationParty | null>;
489
- protected readonly mode: _angular_core.Signal<"candidates" | "active" | "hidden">;
490
- /** Two-letter initials for a delegator avatar (matches the user-menu pattern). */
491
- protected initials(party: DelegationRow['delegator'] | null | undefined): string;
492
- protected start(row: DelegationRow, event: MouseEvent): void;
493
- protected switchTo(row: DelegationRow, event: MouseEvent): void;
494
- protected endSession(event: MouseEvent): void;
515
+ protected readonly isBusy: _angular_core.Signal<boolean>;
516
+ protected readonly onBehalfOf: _angular_core.Signal<DelegationParty | null>;
517
+ /** The real signed-in user host-supplied when available, derived otherwise. */
518
+ protected readonly self: _angular_core.Signal<DelegationParty | null>;
519
+ /** Nothing to switch between and no session running — render nothing. */
520
+ protected readonly visible: _angular_core.Signal<boolean>;
521
+ /** "You", then every delegator. The active identity carries the checkmark. */
522
+ protected readonly identities: _angular_core.Signal<DelegationIdentityOption[]>;
523
+ /** Two-letter initials for an avatar (matches the user-menu pattern). */
524
+ protected initials(party: DelegationParty | null | undefined): string;
525
+ protected select(option: DelegationIdentityOption, event: Event): void;
495
526
  protected onManage(): void;
496
527
  protected loadMore(event: MouseEvent): void;
497
528
  private openConfirm;
498
529
  static ɵfac: _angular_core.ɵɵFactoryDeclaration<DelegationMenuPanel, never>;
499
- static ɵcmp: _angular_core.ɵɵComponentDeclaration<DelegationMenuPanel, "mt-delegation-menu-panel", never, { "managePath": { "alias": "managePath"; "required": false; "isSignal": true; }; "showManageLink": { "alias": "showManageLink"; "required": false; "isSignal": true; }; }, { "closeRequested": "closeRequested"; }, never, never, true, never>;
530
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<DelegationMenuPanel, "mt-delegation-menu-panel", never, { "managePath": { "alias": "managePath"; "required": false; "isSignal": true; }; "showManageLink": { "alias": "showManageLink"; "required": false; "isSignal": true; }; "currentUser": { "alias": "currentUser"; "required": false; "isSignal": true; }; }, { "closeRequested": "closeRequested"; }, never, never, true, never>;
500
531
  }
501
532
 
502
533
  interface StatusVisual {
@@ -1016,7 +1047,9 @@ interface DelegationPromptNamespace {
1016
1047
  * should branch on this — `Logout`, `UserSwitch`, `TenantSwitch` and `AppSwitch`
1017
1048
  * are session teardowns where there is no new actor to load data for.
1018
1049
  */
1019
- type DelegationContextChangeReason = DelegationSessionInvalidationReason | 'StartSession' | 'SwitchSession';
1050
+ type DelegationContextChangeReason = DelegationSessionInvalidationReason | 'StartSession' | 'SwitchSession'
1051
+ /** Re-minted after a page reload — same actor, so the host should stay put. */
1052
+ | 'ResumeSession';
1020
1053
  interface DelegationContextChange {
1021
1054
  previous: ActiveDelegationSession | null;
1022
1055
  current: ActiveDelegationSession | null;
@@ -1034,6 +1067,42 @@ declare function provideDelegationRuntime(config: DelegationRuntimeConfig | Dele
1034
1067
  declare const DELEGATED_RUNTIME_REQUEST: HttpContextToken<boolean>;
1035
1068
  declare function withDelegatedRuntime(context?: HttpContext): HttpContext;
1036
1069
 
1070
+ /**
1071
+ * Lets a delegated session survive a page reload **without persisting the
1072
+ * token**.
1073
+ *
1074
+ * Doc 05 is unambiguous: the delegation access token is memory-only, and it
1075
+ * stays that way — this store keeps a single opaque `delegationId` plus the
1076
+ * owning user/app/tenant namespace. On the next boot the runtime calls
1077
+ * `POST identity/delegations/{id}/session` again and mints a *fresh* token,
1078
+ * which is what doc 09 already prescribes for restarting a session ("use the
1079
+ * newly returned token because the scope hash or delegation version may have
1080
+ * changed"). The backend re-authorizes from scratch every time, so a delegation
1081
+ * that expired, was cancelled, or had its scope revoked while the tab was shut
1082
+ * simply fails to resume and the user stays themselves.
1083
+ *
1084
+ * Never holds a token, a candidate record, a name, or an email.
1085
+ */
1086
+ declare class DelegationSessionResumeStore {
1087
+ private readonly document;
1088
+ private readonly config;
1089
+ remember(delegationId: number): void;
1090
+ /**
1091
+ * The delegation to resume for the *current* user/app/tenant, or `null`. A
1092
+ * marker left by a different actor is dropped rather than honoured, so
1093
+ * signing in as someone else on a shared browser never resumes their
1094
+ * delegation.
1095
+ */
1096
+ pending(): number | null;
1097
+ clear(): void;
1098
+ private namespace;
1099
+ private read;
1100
+ private write;
1101
+ private storage;
1102
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<DelegationSessionResumeStore, never>;
1103
+ static ɵprov: _angular_core.ɵɵInjectableDeclaration<DelegationSessionResumeStore>;
1104
+ }
1105
+
1037
1106
  declare class GetMyDelegations {
1038
1107
  query: DelegationListQuery;
1039
1108
  static readonly type = "[Delegations] Get My Delegations";
@@ -1258,6 +1327,23 @@ declare class StartDelegationSession {
1258
1327
  static readonly type = "[DelegationSession] Start";
1259
1328
  constructor(delegation: DelegationRow);
1260
1329
  }
1330
+ /**
1331
+ * Re-mint the session the user was in before they reloaded the page, from the
1332
+ * persisted delegation id — never a token.
1333
+ *
1334
+ * Pass `delegation` when the row is already in hand; otherwise the state loads
1335
+ * the candidates itself, so a host can await this action **before** the
1336
+ * authenticated shell mounts and boot straight into delegated mode instead of
1337
+ * loading everything twice.
1338
+ *
1339
+ * Completes quietly when there is nothing to resume or the delegation is no
1340
+ * longer startable — the user simply stays themselves.
1341
+ */
1342
+ declare class ResumeDelegationSession {
1343
+ delegation: DelegationRow | null;
1344
+ static readonly type = "[DelegationSession] Resume";
1345
+ constructor(delegation?: DelegationRow | null);
1346
+ }
1261
1347
  /** End the current delegated session. Client-local only (doc 05). */
1262
1348
  declare class EndDelegationSession {
1263
1349
  reason: DelegationSessionInvalidationReason;
@@ -1286,6 +1372,9 @@ declare class DelegationSessionState {
1286
1372
  * or open the availability prompt — after sign-out.
1287
1373
  */
1288
1374
  private candidatesGeneration;
1375
+ private resumeStore;
1376
+ /** One resume attempt per page load — a dead delegation must not retry. */
1377
+ private resumeAttempted;
1289
1378
  constructor();
1290
1379
  static getActive(state: DelegationSessionStateModel): ActiveDelegationSession | null;
1291
1380
  static getCandidates(state: DelegationSessionStateModel): DelegationRow[];
@@ -1294,6 +1383,17 @@ declare class DelegationSessionState {
1294
1383
  static getLoadingActive(state: DelegationSessionStateModel): string[];
1295
1384
  static getErrors(state: DelegationSessionStateModel): Record<string, string | null | undefined>;
1296
1385
  loadCandidates(ctx: StateContext<DelegationSessionStateModel>, { page, pageSize, append }: LoadDelegationCandidates): rxjs.Observable<Response<DelegationPage<DelegationRow>>>;
1386
+ /**
1387
+ * Fallback resume for hosts that do not await {@link ResumeDelegationSession}
1388
+ * before mounting their authenticated shell: pick the session back up as soon
1389
+ * as the candidates arrive.
1390
+ *
1391
+ * Prefer the awaited path — resuming after the shell has already loaded means
1392
+ * every actor-scoped read runs twice, once as the real user and again under
1393
+ * delegated authority.
1394
+ */
1395
+ private tryResume;
1396
+ resume(ctx: StateContext<DelegationSessionStateModel>, { delegation }: ResumeDelegationSession): rxjs.Observable<void>;
1297
1397
  start(ctx: StateContext<DelegationSessionStateModel>, { delegation }: StartDelegationSession): rxjs.Observable<void>;
1298
1398
  private startSession;
1299
1399
  end(ctx: StateContext<DelegationSessionStateModel>, { reason }: EndDelegationSession): rxjs.Observable<void>;
@@ -1307,6 +1407,7 @@ declare class DelegationSessionState {
1307
1407
  declare class DelegationSessionFacade {
1308
1408
  private readonly store;
1309
1409
  private readonly promptReceipts;
1410
+ private readonly resumeStore;
1310
1411
  private endInFlight;
1311
1412
  readonly active: _angular_core.Signal<_masterteam_delegations.ActiveDelegationSession | null>;
1312
1413
  readonly candidates: _angular_core.Signal<DelegationRow[]>;
@@ -1315,8 +1416,13 @@ declare class DelegationSessionFacade {
1315
1416
  private readonly loadingActive;
1316
1417
  /** On-behalf-of (delegator). */
1317
1418
  readonly onBehalfOf: _angular_core.Signal<_masterteam_delegations.DelegationParty | null>;
1318
- /** Executed-by (actual logged-in / delegated user). */
1319
- readonly executedBy: _angular_core.Signal<_masterteam_delegations.DelegationParty | null>;
1419
+ /**
1420
+ * Executed-by (the real signed-in user), known whether or not a session is
1421
+ * active: every assigned row carries the current user as its `delegatedUser`,
1422
+ * so the account switcher can list "you" alongside the delegators without the
1423
+ * package depending on the host's auth state.
1424
+ */
1425
+ readonly executedBy: _angular_core.Signal<_masterteam_delegations.DelegationParty>;
1320
1426
  readonly hasCandidates: _angular_core.Signal<boolean>;
1321
1427
  readonly hasMoreCandidates: _angular_core.Signal<boolean>;
1322
1428
  readonly isStarting: _angular_core.Signal<boolean>;
@@ -1324,6 +1430,19 @@ declare class DelegationSessionFacade {
1324
1430
  loadCandidates(page?: number, pageSize?: number, append?: boolean): Observable<void>;
1325
1431
  loadMoreCandidates(): Observable<void>;
1326
1432
  claimPromptCandidates(candidates: DelegationRow[]): Promise<DelegationRow[]>;
1433
+ /**
1434
+ * True when a previous session is waiting to be re-minted after a reload.
1435
+ * Synchronous (a `localStorage` read), so a route guard can check it without
1436
+ * paying for a round-trip on the overwhelmingly common no-delegation boot.
1437
+ */
1438
+ hasPendingResume(): boolean;
1439
+ /**
1440
+ * Re-mints the delegated session the user reloaded out of, and completes when
1441
+ * delegated mode is in force (or when there is nothing to resume). Await this
1442
+ * **before** mounting the authenticated shell so its reads run once, already
1443
+ * delegated.
1444
+ */
1445
+ resumeSession(): Observable<void>;
1327
1446
  startSession(delegation: DelegationRow): Observable<void>;
1328
1447
  switchSession(delegation: DelegationRow): Observable<void>;
1329
1448
  endSession(reason?: DelegationSessionInvalidationReason): Observable<unknown>;
@@ -1331,5 +1450,5 @@ declare class DelegationSessionFacade {
1331
1450
  static ɵprov: _angular_core.ɵɵInjectableDeclaration<DelegationSessionFacade>;
1332
1451
  }
1333
1452
 
1334
- export { ApproveDelegation, CancelDelegation, ClearDelegationDetail, ClearScopePreview, CreateDelegationLegacy, CreateDelegationV2, DELEGATED_RUNTIME_REQUEST, DELEGATION_RUNTIME_CONFIG, DelegationDetailDrawer, DelegationForm, DelegationMenuPanel, DelegationSessionActionKey, DelegationSessionFacade, DelegationSessionState, DelegationStatusChip, Delegations, DelegationsActionKey, DelegationsFacade, DelegationsList, DelegationsState, EndDelegationSession, GetActiveAssignedDelegations, GetAdminDelegations, GetApprovalDelegations, GetAssignedDelegations, GetDelegationDetail, GetMyDelegations, GetScopeOptions, LoadDelegationCandidates, PreviewScope, RejectDelegation, RejectDelegationDialog, ScopePicker, StartDelegationSession, StartSessionDialog, SwitchDelegationSession, TopbarDelegationMenu, UpdateDelegationLegacy, UpdateDelegationV2, appDelegationInterceptor, provideDelegationRuntime, withDelegatedRuntime };
1453
+ export { ApproveDelegation, CancelDelegation, ClearDelegationDetail, ClearScopePreview, CreateDelegationLegacy, CreateDelegationV2, DELEGATED_RUNTIME_REQUEST, DELEGATION_RUNTIME_CONFIG, DelegationDetailDrawer, DelegationForm, DelegationMenuPanel, DelegationSessionActionKey, DelegationSessionFacade, DelegationSessionResumeStore, DelegationSessionState, DelegationStatusChip, Delegations, DelegationsActionKey, DelegationsFacade, DelegationsList, DelegationsState, EndDelegationSession, GetActiveAssignedDelegations, GetAdminDelegations, GetApprovalDelegations, GetAssignedDelegations, GetDelegationDetail, GetMyDelegations, GetScopeOptions, LoadDelegationCandidates, PreviewScope, RejectDelegation, RejectDelegationDialog, ResumeDelegationSession, ScopePicker, StartDelegationSession, StartSessionDialog, SwitchDelegationSession, TopbarDelegationMenu, UpdateDelegationLegacy, UpdateDelegationV2, appDelegationInterceptor, provideDelegationRuntime, withDelegatedRuntime };
1335
1454
  export type { ActiveDelegationSession, AdminCreateDelegationV2Request, AdminUpdateDelegationV2Request, ApproveDelegationRequest, CreateDelegationLegacyRequest, CreateDelegationV2Request, DelegationAllowedAction, DelegationAppAccessibility, DelegationApprovalInfo, DelegationApprovalStatus, DelegationCancellationInfo, DelegationContextChange, DelegationContextChangeReason, DelegationDayRuleMode, DelegationDetail, DelegationDisplayValue, DelegationDto, DelegationEffectiveStatus, DelegationGrant, DelegationListQuery, DelegationPage, DelegationParty, DelegationPromptNamespace, DelegationRow, DelegationRuntimeConfig, DelegationScopeAction, DelegationScopeCombinationRule, DelegationScopeDeniedItem, DelegationScopeFact, DelegationScopeHierarchyGroup, DelegationScopeHierarchyTarget, DelegationScopeLevelNode, DelegationScopeModuleNode, DelegationScopeOptions, DelegationScopePermissionGroup, DelegationScopePreview, DelegationScopePreviewRequest, DelegationScopeSelection, DelegationScopeTarget, DelegationScopeView, DelegationScopeViewLevel, DelegationScopeViewModule, DelegationScopeViewOperation, DelegationScopeViewTemplate, DelegationScopeWarning, DelegationSessionInvalidationReason, DelegationSessionStartResponse, DelegationSessionStateModel, DelegationSortDirection, DelegationStatusInfo, DelegationsStateModel, RejectDelegationRequest, UpdateDelegationLegacyRequest, UpdateDelegationV2Request };