@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.cjs CHANGED
@@ -106,6 +106,12 @@ var auth = {
106
106
  externalLoginRememberChoice: `${authRoot}/external-login/remember-choice`,
107
107
  /** POST — swap the current cookie for the user's alt identity (the contact↔systemuser sibling). */
108
108
  switchIdentity: `${authRoot}/switch-identity`,
109
+ /** POST — start impersonating a portal contact. Internal users holding the SystemAdmin role only. */
110
+ impersonate: `${authRoot}/impersonate`,
111
+ /** POST — end an impersonation session. Takes no body; the user to return to comes from the session's claims. */
112
+ stopImpersonation: `${authRoot}/stop-impersonation`,
113
+ /** POST — search portal contacts for the impersonation picker. */
114
+ impersonateSearch: `${authRoot}/impersonate/search`,
109
115
  /** GET — snapshot of the current user (or anonymous shape). */
110
116
  me: `${authRoot}/me`,
111
117
  /** Account-management endpoints under `/api/auth/manage/*`. */
@@ -553,6 +559,51 @@ var AuthClient = class {
553
559
  bodyAndSignal(void 0, signal)
554
560
  );
555
561
  }
562
+ // --- Impersonation ---------------------------------------------------------------
563
+ /**
564
+ * Starts impersonating a portal contact, swapping the auth cookie for theirs. Restricted
565
+ * server-side to internal users holding the `SystemAdmin` role; the target is resolved through
566
+ * the contact store alone, so a systemuser id can't be supplied to assume a staff identity.
567
+ *
568
+ * On `ImpersonateResult.Started` the session IS that contact — `/api/auth/me` reports the
569
+ * contact's id, roles and user type, with only `isImpersonating` / `impersonator*` betraying
570
+ * who is behind it. Reload or re-fetch the user after this resolves; anything already rendered
571
+ * was rendered for the previous identity.
572
+ */
573
+ impersonateAsync(targetUserId, signal) {
574
+ return this.transport.sendJson(
575
+ "POST",
576
+ Routes.api.auth.impersonate,
577
+ bodyAndSignal({ targetUserId }, signal)
578
+ );
579
+ }
580
+ /**
581
+ * Ends an impersonation session and signs the internal user back in. Takes no parameters — the
582
+ * identity to return to is read from the session's own claims server-side, so a caller can't
583
+ * choose who it becomes on the way back.
584
+ */
585
+ stopImpersonationAsync(signal) {
586
+ return this.transport.sendJson(
587
+ "POST",
588
+ Routes.api.auth.stopImpersonation,
589
+ bodyAndSignal(void 0, signal)
590
+ );
591
+ }
592
+ /**
593
+ * Searches portal contacts that may be impersonated. A query that parses as a GUID is an exact
594
+ * user-id lookup; otherwise it matches full name and email columns, and queries shorter than
595
+ * three characters return nothing.
596
+ *
597
+ * Returns an empty result rather than failing when the caller isn't permitted to impersonate,
598
+ * so a picker renders "no matches" without learning which condition applied.
599
+ */
600
+ searchImpersonationTargetsAsync(query, signal) {
601
+ return this.transport.sendJson(
602
+ "POST",
603
+ Routes.api.auth.impersonateSearch,
604
+ bodyAndSignal({ query }, signal)
605
+ );
606
+ }
556
607
  // --- Profile ---------------------------------------------------------------------
557
608
  /** Reads the signed-in user's manage-profile snapshot (Identity status + linked contact fields). */
558
609
  getProfileAsync(signal) {
@@ -1331,6 +1382,16 @@ var ChartDateGrouping = {
1331
1382
  /** Group by quarter + year. Label: "Q1 2024". */
1332
1383
  QuarterAndYear: 10
1333
1384
  };
1385
+ var ColumnSecurityPermission = {
1386
+ /** The column can be neither read nor written. */
1387
+ None: 0,
1388
+ /** The column's real value is returned. */
1389
+ Read: 1,
1390
+ /** The column can be included in a create or update. */
1391
+ Write: 2,
1392
+ /** Full access — the default for every column not listed in ColumnPermissions. */
1393
+ All: 3
1394
+ };
1334
1395
  var ColumnType = {
1335
1396
  /** A Boolean attribute. Value = 0. */
1336
1397
  Boolean: 0,
@@ -1425,6 +1486,20 @@ var FileArchiveResponseFormat = {
1425
1486
  /** 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. */
1426
1487
  Json: 1
1427
1488
  };
1489
+ var ImpersonateResult = {
1490
+ /** The target contact was signed in and the auth cookie has been swapped. */
1491
+ Started: 0,
1492
+ /** The current request is unauthenticated. */
1493
+ NotAuthenticated: 1,
1494
+ /** 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). */
1495
+ NotAuthorized: 2,
1496
+ /** 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. */
1497
+ TargetNotFound: 3,
1498
+ /** The contact exists but the host's impersonation target filter rejected it. */
1499
+ TargetNotImpersonatable: 4,
1500
+ /** The session is already impersonating. Nesting isn't supported — it would make the return path order-dependent — so stop the current impersonation first. */
1501
+ AlreadyImpersonating: 5
1502
+ };
1428
1503
  var JoinOperator = {
1429
1504
  /** Inner join — only matching rows are returned. */
1430
1505
  Inner: 0,
@@ -1515,6 +1590,16 @@ var ResetPasswordResult = {
1515
1590
  /** 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. */
1516
1591
  InvalidPassword: 2
1517
1592
  };
1593
+ var StopImpersonationResult = {
1594
+ /** Impersonation ended and the auth cookie is back to the internal user. */
1595
+ Stopped: 0,
1596
+ /** The session wasn't impersonating — there was nothing to stop. */
1597
+ NotImpersonating: 1,
1598
+ /** 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. */
1599
+ ImpersonatorNotFound: 2,
1600
+ /** The current request is unauthenticated. */
1601
+ NotAuthenticated: 3
1602
+ };
1518
1603
  var SwitchIdentityResult = {
1519
1604
  /** The alt identity was signed in and the auth cookie has been swapped. */
1520
1605
  Switched: 0,
@@ -1560,6 +1645,18 @@ var ViewType = {
1560
1645
  LookupDisplay: 2048
1561
1646
  };
1562
1647
 
1648
+ // src/column-permissions.ts
1649
+ function getColumnPermissions(record, columnName) {
1650
+ const columnPermissions = record?.columnPermissions?.[columnName];
1651
+ return columnPermissions ?? ColumnSecurityPermission.All;
1652
+ }
1653
+ function canReadColumn(record, columnName) {
1654
+ return (getColumnPermissions(record, columnName) & ColumnSecurityPermission.Read) === ColumnSecurityPermission.Read;
1655
+ }
1656
+ function canWriteColumn(record, columnName) {
1657
+ return (getColumnPermissions(record, columnName) & ColumnSecurityPermission.Write) === ColumnSecurityPermission.Write;
1658
+ }
1659
+
1563
1660
  // src/record-id.ts
1564
1661
  var EMPTY_GUID = "00000000-0000-0000-0000-000000000000";
1565
1662
  function getRecordReferenceId(record) {
@@ -1579,6 +1676,7 @@ exports.AuthClient = AuthClient;
1579
1676
  exports.ChangeEmailResult = ChangeEmailResult;
1580
1677
  exports.ChangePasswordResult = ChangePasswordResult;
1581
1678
  exports.ChartDateGrouping = ChartDateGrouping;
1679
+ exports.ColumnSecurityPermission = ColumnSecurityPermission;
1582
1680
  exports.ColumnType = ColumnType;
1583
1681
  exports.ConfirmExternalLoginResult = ConfirmExternalLoginResult;
1584
1682
  exports.DateTimeBehavior = DateTimeBehavior;
@@ -1586,6 +1684,7 @@ exports.DeletePersonalDataResult = DeletePersonalDataResult;
1586
1684
  exports.EntityRole = EntityRole;
1587
1685
  exports.ExternalLoginCandidateKind = ExternalLoginCandidateKind;
1588
1686
  exports.FileArchiveResponseFormat = FileArchiveResponseFormat;
1687
+ exports.ImpersonateResult = ImpersonateResult;
1589
1688
  exports.InvalidOperationError = InvalidOperationError;
1590
1689
  exports.JoinOperator = JoinOperator;
1591
1690
  exports.LocalizationSourceKind = LocalizationSourceKind;
@@ -1599,12 +1698,16 @@ exports.RelationshipFilterMode = RelationshipFilterMode;
1599
1698
  exports.RequiredLevel = RequiredLevel;
1600
1699
  exports.ResetPasswordResult = ResetPasswordResult;
1601
1700
  exports.Routes = Routes;
1701
+ exports.StopImpersonationResult = StopImpersonationResult;
1602
1702
  exports.SwitchIdentityResult = SwitchIdentityResult;
1603
1703
  exports.TableSecurityPermission = TableSecurityPermission;
1604
1704
  exports.Transport = Transport;
1605
1705
  exports.UnauthorizedAccessError = UnauthorizedAccessError;
1606
1706
  exports.VERSION = VERSION;
1607
1707
  exports.ViewType = ViewType;
1708
+ exports.canReadColumn = canReadColumn;
1709
+ exports.canWriteColumn = canWriteColumn;
1710
+ exports.getColumnPermissions = getColumnPermissions;
1608
1711
  exports.getRecordReferenceId = getRecordReferenceId;
1609
1712
  exports.mapProblemDetails = mapProblemDetails;
1610
1713
  //# sourceMappingURL=index.cjs.map