@powerportalspro/core 6.1.0 → 7.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/dist/index.js CHANGED
@@ -104,6 +104,12 @@ var auth = {
104
104
  externalLoginRememberChoice: `${authRoot}/external-login/remember-choice`,
105
105
  /** POST — swap the current cookie for the user's alt identity (the contact↔systemuser sibling). */
106
106
  switchIdentity: `${authRoot}/switch-identity`,
107
+ /** POST — start impersonating a portal contact. Internal users holding the SystemAdmin role only. */
108
+ impersonate: `${authRoot}/impersonate`,
109
+ /** POST — end an impersonation session. Takes no body; the user to return to comes from the session's claims. */
110
+ stopImpersonation: `${authRoot}/stop-impersonation`,
111
+ /** POST — search portal contacts for the impersonation picker. */
112
+ impersonateSearch: `${authRoot}/impersonate/search`,
107
113
  /** GET — snapshot of the current user (or anonymous shape). */
108
114
  me: `${authRoot}/me`,
109
115
  /** Account-management endpoints under `/api/auth/manage/*`. */
@@ -551,6 +557,51 @@ var AuthClient = class {
551
557
  bodyAndSignal(void 0, signal)
552
558
  );
553
559
  }
560
+ // --- Impersonation ---------------------------------------------------------------
561
+ /**
562
+ * Starts impersonating a portal contact, swapping the auth cookie for theirs. Restricted
563
+ * server-side to internal users holding the `SystemAdmin` role; the target is resolved through
564
+ * the contact store alone, so a systemuser id can't be supplied to assume a staff identity.
565
+ *
566
+ * On `ImpersonateResult.Started` the session IS that contact — `/api/auth/me` reports the
567
+ * contact's id, roles and user type, with only `isImpersonating` / `impersonator*` betraying
568
+ * who is behind it. Reload or re-fetch the user after this resolves; anything already rendered
569
+ * was rendered for the previous identity.
570
+ */
571
+ impersonateAsync(targetUserId, signal) {
572
+ return this.transport.sendJson(
573
+ "POST",
574
+ Routes.api.auth.impersonate,
575
+ bodyAndSignal({ targetUserId }, signal)
576
+ );
577
+ }
578
+ /**
579
+ * Ends an impersonation session and signs the internal user back in. Takes no parameters — the
580
+ * identity to return to is read from the session's own claims server-side, so a caller can't
581
+ * choose who it becomes on the way back.
582
+ */
583
+ stopImpersonationAsync(signal) {
584
+ return this.transport.sendJson(
585
+ "POST",
586
+ Routes.api.auth.stopImpersonation,
587
+ bodyAndSignal(void 0, signal)
588
+ );
589
+ }
590
+ /**
591
+ * Searches portal contacts that may be impersonated. A query that parses as a GUID is an exact
592
+ * user-id lookup; otherwise it matches full name and email columns, and queries shorter than
593
+ * three characters return nothing.
594
+ *
595
+ * Returns an empty result rather than failing when the caller isn't permitted to impersonate,
596
+ * so a picker renders "no matches" without learning which condition applied.
597
+ */
598
+ searchImpersonationTargetsAsync(query, signal) {
599
+ return this.transport.sendJson(
600
+ "POST",
601
+ Routes.api.auth.impersonateSearch,
602
+ bodyAndSignal({ query }, signal)
603
+ );
604
+ }
554
605
  // --- Profile ---------------------------------------------------------------------
555
606
  /** Reads the signed-in user's manage-profile snapshot (Identity status + linked contact fields). */
556
607
  getProfileAsync(signal) {
@@ -1329,6 +1380,16 @@ var ChartDateGrouping = {
1329
1380
  /** Group by quarter + year. Label: "Q1 2024". */
1330
1381
  QuarterAndYear: 10
1331
1382
  };
1383
+ var ColumnSecurityPermission = {
1384
+ /** The column can be neither read nor written. */
1385
+ None: 0,
1386
+ /** The column's real value is returned. */
1387
+ Read: 1,
1388
+ /** The column can be included in a create or update. */
1389
+ Write: 2,
1390
+ /** Full access — the default for every column not listed in ColumnPermissions. */
1391
+ All: 3
1392
+ };
1332
1393
  var ColumnType = {
1333
1394
  /** A Boolean attribute. Value = 0. */
1334
1395
  Boolean: 0,
@@ -1423,6 +1484,20 @@ var FileArchiveResponseFormat = {
1423
1484
  /** Returns a JSON envelope (FileArchiveJsonResponse) that wraps the archive's bytes as base64. Useful when the consumer wants to inspect headers / filename / size programmatically before triggering a download, or when the host environment can't stream binary responses (some test harnesses, some service workers). Trades ~33% wire-size overhead for the JSON wrapper. */
1424
1485
  Json: 1
1425
1486
  };
1487
+ var ImpersonateResult = {
1488
+ /** The target contact was signed in and the auth cookie has been swapped. */
1489
+ Started: 0,
1490
+ /** The current request is unauthenticated. */
1491
+ NotAuthenticated: 1,
1492
+ /** The caller may not impersonate — either they don't hold the SystemAdmin role, or they aren't a real internal systemuser (a contact backed by a stub systemuser is still a portal contact and can never impersonate). */
1493
+ NotAuthorized: 2,
1494
+ /** No active contact exists with the requested id. Also returned when the id belongs to a systemuser — the lookup only ever consults the contact store, so an internal user's id simply doesn't resolve. */
1495
+ TargetNotFound: 3,
1496
+ /** The contact exists but the host's impersonation target filter rejected it. */
1497
+ TargetNotImpersonatable: 4,
1498
+ /** The session is already impersonating. Nesting isn't supported — it would make the return path order-dependent — so stop the current impersonation first. */
1499
+ AlreadyImpersonating: 5
1500
+ };
1426
1501
  var JoinOperator = {
1427
1502
  /** Inner join — only matching rows are returned. */
1428
1503
  Inner: 0,
@@ -1513,6 +1588,16 @@ var ResetPasswordResult = {
1513
1588
  /** The new password did not satisfy the host's password rules. The accompanying ProblemDetails (in the failed-validation HTTP 400) carries the per-rule error messages from IdentityResult.Errors. */
1514
1589
  InvalidPassword: 2
1515
1590
  };
1591
+ var StopImpersonationResult = {
1592
+ /** Impersonation ended and the auth cookie is back to the internal user. */
1593
+ Stopped: 0,
1594
+ /** The session wasn't impersonating — there was nothing to stop. */
1595
+ NotImpersonating: 1,
1596
+ /** The internal user recorded on the session no longer resolves (disabled or removed in Dataverse mid-session). The impersonated session is signed out rather than left running, so the caller ends up anonymous and must sign in again. */
1597
+ ImpersonatorNotFound: 2,
1598
+ /** The current request is unauthenticated. */
1599
+ NotAuthenticated: 3
1600
+ };
1516
1601
  var SwitchIdentityResult = {
1517
1602
  /** The alt identity was signed in and the auth cookie has been swapped. */
1518
1603
  Switched: 0,
@@ -1558,6 +1643,18 @@ var ViewType = {
1558
1643
  LookupDisplay: 2048
1559
1644
  };
1560
1645
 
1646
+ // src/column-permissions.ts
1647
+ function getColumnPermissions(record, columnName) {
1648
+ const columnPermissions = record?.columnPermissions?.[columnName];
1649
+ return columnPermissions ?? ColumnSecurityPermission.All;
1650
+ }
1651
+ function canReadColumn(record, columnName) {
1652
+ return (getColumnPermissions(record, columnName) & ColumnSecurityPermission.Read) === ColumnSecurityPermission.Read;
1653
+ }
1654
+ function canWriteColumn(record, columnName) {
1655
+ return (getColumnPermissions(record, columnName) & ColumnSecurityPermission.Write) === ColumnSecurityPermission.Write;
1656
+ }
1657
+
1561
1658
  // src/record-id.ts
1562
1659
  var EMPTY_GUID = "00000000-0000-0000-0000-000000000000";
1563
1660
  function getRecordReferenceId(record) {
@@ -1569,6 +1666,6 @@ function getRecordReferenceId(record) {
1569
1666
  // src/index.ts
1570
1667
  var VERSION = "0.1.0";
1571
1668
 
1572
- export { AggregateType, ArchiveFormat, ArgumentError, ArgumentNullError, AuthClient, ChangeEmailResult, ChangePasswordResult, ChartDateGrouping, ColumnType, ConfirmExternalLoginResult, DateTimeBehavior, DeletePersonalDataResult, EntityRole, ExternalLoginCandidateKind, FileArchiveResponseFormat, InvalidOperationError, JoinOperator, LocalizationSourceKind, LocalizationSourceStatus, LoginResult, PortalUserType, PowerPortalsProClient, PowerPortalsProError, RegisterResult, RelationshipFilterMode, RequiredLevel, ResetPasswordResult, Routes, SwitchIdentityResult, TableSecurityPermission, Transport, UnauthorizedAccessError, VERSION, ViewType, getRecordReferenceId, mapProblemDetails };
1669
+ export { AggregateType, ArchiveFormat, ArgumentError, ArgumentNullError, AuthClient, ChangeEmailResult, ChangePasswordResult, ChartDateGrouping, ColumnSecurityPermission, ColumnType, ConfirmExternalLoginResult, DateTimeBehavior, DeletePersonalDataResult, EntityRole, ExternalLoginCandidateKind, FileArchiveResponseFormat, ImpersonateResult, InvalidOperationError, JoinOperator, LocalizationSourceKind, LocalizationSourceStatus, LoginResult, PortalUserType, PowerPortalsProClient, PowerPortalsProError, RegisterResult, RelationshipFilterMode, RequiredLevel, ResetPasswordResult, Routes, StopImpersonationResult, SwitchIdentityResult, TableSecurityPermission, Transport, UnauthorizedAccessError, VERSION, ViewType, canReadColumn, canWriteColumn, getColumnPermissions, getRecordReferenceId, mapProblemDetails };
1573
1670
  //# sourceMappingURL=index.js.map
1574
1671
  //# sourceMappingURL=index.js.map