@uipath/uipath-typescript 1.4.2 → 1.5.1

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.
Files changed (52) hide show
  1. package/README.md +7 -1
  2. package/dist/agent-memory/index.d.ts +4 -1
  3. package/dist/agents/index.cjs +341 -6
  4. package/dist/agents/index.d.ts +717 -16
  5. package/dist/agents/index.mjs +342 -7
  6. package/dist/assets/index.cjs +132 -15
  7. package/dist/assets/index.d.ts +12 -1
  8. package/dist/assets/index.mjs +132 -15
  9. package/dist/attachments/index.cjs +120 -12
  10. package/dist/attachments/index.mjs +120 -12
  11. package/dist/buckets/index.cjs +136 -15
  12. package/dist/buckets/index.d.ts +12 -1
  13. package/dist/buckets/index.mjs +136 -15
  14. package/dist/cases/index.cjs +1203 -938
  15. package/dist/cases/index.d.ts +325 -45
  16. package/dist/cases/index.mjs +1203 -938
  17. package/dist/conversational-agent/index.cjs +48 -10
  18. package/dist/conversational-agent/index.d.ts +117 -6
  19. package/dist/conversational-agent/index.mjs +48 -10
  20. package/dist/core/index.cjs +1 -1
  21. package/dist/core/index.mjs +1 -1
  22. package/dist/entities/index.cjs +448 -9
  23. package/dist/entities/index.d.ts +441 -1
  24. package/dist/entities/index.mjs +447 -10
  25. package/dist/feedback/index.cjs +25 -9
  26. package/dist/feedback/index.mjs +25 -9
  27. package/dist/index.cjs +1281 -330
  28. package/dist/index.d.ts +1988 -143
  29. package/dist/index.mjs +1282 -331
  30. package/dist/index.umd.js +1230 -279
  31. package/dist/jobs/index.cjs +141 -19
  32. package/dist/jobs/index.d.ts +22 -6
  33. package/dist/jobs/index.mjs +141 -19
  34. package/dist/maestro-processes/index.cjs +553 -354
  35. package/dist/maestro-processes/index.d.ts +376 -47
  36. package/dist/maestro-processes/index.mjs +553 -354
  37. package/dist/notifications/index.cjs +2012 -0
  38. package/dist/notifications/index.d.ts +615 -0
  39. package/dist/notifications/index.mjs +2010 -0
  40. package/dist/processes/index.cjs +118 -18
  41. package/dist/processes/index.d.ts +18 -2
  42. package/dist/processes/index.mjs +118 -18
  43. package/dist/queues/index.cjs +131 -14
  44. package/dist/queues/index.d.ts +12 -1
  45. package/dist/queues/index.mjs +131 -14
  46. package/dist/tasks/index.cjs +125 -13
  47. package/dist/tasks/index.d.ts +4 -1
  48. package/dist/tasks/index.mjs +125 -13
  49. package/dist/traces/index.cjs +220 -6
  50. package/dist/traces/index.d.ts +360 -25
  51. package/dist/traces/index.mjs +221 -7
  52. package/package.json +14 -4
@@ -974,7 +974,16 @@ const BUCKET_TOKEN_PARAMS = {
974
974
  * Returns the original value if parsing fails.
975
975
  */
976
976
  /**
977
- * Transforms data by mapping fields according to the provided field mapping
977
+ * Transforms data by renaming each key in `data` exactly once, using the
978
+ * mapping (`sourceField → targetField`). Keys not present in the mapping
979
+ * pass through unchanged. The original (pre-rename) key is dropped — the
980
+ * result contains only the renamed key.
981
+ *
982
+ * Each rename is independent. If the mapping happens to contain chained
983
+ * entries (`a → b` and `b → c`), they do NOT compose: a field named `a`
984
+ * in `data` becomes `b` (not `c`), because the renames are applied based
985
+ * on the original data's keys, not the running result.
986
+ *
978
987
  * @param data The source data to transform
979
988
  * @param fieldMapping Object mapping source field names to target field names
980
989
  * @returns Transformed data with mapped field names
@@ -997,21 +1006,28 @@ const BUCKET_TOKEN_PARAMS = {
997
1006
  * // { userId: '123', name: 'john' },
998
1007
  * // { userId: '456', name: 'jane' }
999
1008
  * // ]
1009
+ *
1010
+ * // No chaining — `a → b` does not become `a → c` even if the map has `b → c`.
1011
+ * transformData({ a: 1 }, { a: 'b', b: 'c' });
1012
+ * // result = { b: 1 }
1000
1013
  * ```
1001
1014
  */
1002
1015
  function transformData(data, fieldMapping) {
1016
+ // Pass null/undefined through unchanged — callers (e.g. AttachmentService.getById)
1017
+ // may invoke this on optional fields that an OData `select` excluded.
1018
+ if (data == null) {
1019
+ return data;
1020
+ }
1003
1021
  // Handle array of objects
1004
1022
  if (Array.isArray(data)) {
1005
1023
  return data.map(item => transformData(item, fieldMapping));
1006
1024
  }
1007
- // Handle single object
1008
- const result = { ...data };
1009
- for (const [sourceField, targetField] of Object.entries(fieldMapping)) {
1010
- if (sourceField in result) {
1011
- const value = result[sourceField];
1012
- delete result[sourceField];
1013
- result[targetField] = value;
1014
- }
1025
+ // Walk the ORIGINAL data's keys, look up each in the mapping. One rename
1026
+ // per data key — no mutation of an in-progress result, so chains can't form.
1027
+ const result = {};
1028
+ for (const [key, value] of Object.entries(data)) {
1029
+ const renamedKey = fieldMapping[key] ?? key;
1030
+ result[renamedKey] = value;
1015
1031
  }
1016
1032
  return result;
1017
1033
  }
@@ -1998,6 +2014,14 @@ const DATA_FABRIC_ENDPOINTS = {
1998
2014
  UPDATE_BY_NAME: (choiceSetName, valueId) => `${DATAFABRIC_BASE}/api/EntityService/${choiceSetName}/choiceset/${valueId}/update`,
1999
2015
  DELETE_BY_ID: (choiceSetId) => `${DATAFABRIC_BASE}/api/EntityService/entity/${choiceSetId}/choiceset/delete`,
2000
2016
  },
2017
+ ROLES: {
2018
+ GET_ALL: `${DATAFABRIC_BASE}/api/v2/Role`,
2019
+ },
2020
+ DIRECTORY: {
2021
+ GET_ALL: `${DATAFABRIC_BASE}/api/Directory`,
2022
+ ASSIGN_ROLES: `${DATAFABRIC_BASE}/api/Directory/Role`,
2023
+ REVOKE_ROLES: `${DATAFABRIC_BASE}/api/Directory/RevokeRole`,
2024
+ },
2001
2025
  };
2002
2026
 
2003
2027
  /**
@@ -3790,4 +3814,417 @@ __decorate([
3790
3814
  track('Choicesets.DeleteValuesById')
3791
3815
  ], ChoiceSetService.prototype, "deleteValuesById", null);
3792
3816
 
3793
- export { ChoiceSetService, ChoiceSetService as ChoiceSets, DataDirectionType, EntityService as Entities, EntityAggregateFunction, EntityFieldDataType, EntityService, EntityType, FieldDisplayType, JoinType, LogicalOperator, QueryFilterOperator, ReferenceType, createEntityWithMethods };
3817
+ /**
3818
+ * @internal
3819
+ */
3820
+ var DataFabricRoleType;
3821
+ (function (DataFabricRoleType) {
3822
+ DataFabricRoleType["System"] = "System";
3823
+ DataFabricRoleType["UserDefined"] = "UserDefined";
3824
+ })(DataFabricRoleType || (DataFabricRoleType = {}));
3825
+
3826
+ function isRecord$1(value) {
3827
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
3828
+ }
3829
+ function isDataFabricRole(value) {
3830
+ if (!isRecord$1(value)) {
3831
+ return false;
3832
+ }
3833
+ const { id, name, type, directoryEntityCount, folderId } = value;
3834
+ const hasValidDirectoryEntityCount = directoryEntityCount === undefined ||
3835
+ directoryEntityCount === null ||
3836
+ typeof directoryEntityCount === 'number';
3837
+ const hasValidFolderId = folderId === undefined || typeof folderId === 'string';
3838
+ return typeof id === 'string' &&
3839
+ typeof name === 'string' &&
3840
+ (type === DataFabricRoleType.System || type === DataFabricRoleType.UserDefined) &&
3841
+ hasValidDirectoryEntityCount &&
3842
+ hasValidFolderId;
3843
+ }
3844
+ function validateRolesResponse(data) {
3845
+ if (Array.isArray(data) && data.every(isDataFabricRole)) {
3846
+ return data;
3847
+ }
3848
+ throw new ServerError({
3849
+ message: 'Invalid Data Fabric roles response format.',
3850
+ });
3851
+ }
3852
+ /**
3853
+ * @internal
3854
+ */
3855
+ class DataFabricRoleService extends BaseService {
3856
+ /**
3857
+ * Lists Data Fabric access roles.
3858
+ *
3859
+ * Returns tenant Data Fabric roles such as Admin, Designer, DataWriter, and
3860
+ * DataReader. Role IDs from this method can be passed to
3861
+ * `DataFabricDirectoryService.assignRoles()`.
3862
+ *
3863
+ * @param options - Optional query options
3864
+ * @returns Promise resolving to an array of {@link DataFabricRole}
3865
+ *
3866
+ * @example
3867
+ * ```typescript
3868
+ * import { DataFabricRoleService } from '@uipath/uipath-typescript/entities';
3869
+ *
3870
+ * const roles = new DataFabricRoleService(sdk);
3871
+ * const allRoles = await roles.getAll();
3872
+ * const dataWriter = allRoles.find(role => role.name === 'DataWriter');
3873
+ * ```
3874
+ *
3875
+ * @example
3876
+ * ```typescript
3877
+ * const rolesWithoutStats = await roles.getAll({ stats: false });
3878
+ * ```
3879
+ *
3880
+ * @example
3881
+ * ```typescript
3882
+ * const folderRoles = await roles.getAll({ folderKey: '<folder-key>' });
3883
+ * ```
3884
+ *
3885
+ * @internal
3886
+ */
3887
+ async getAll(options = {}) {
3888
+ const params = createParams({
3889
+ stats: options.stats ?? true,
3890
+ });
3891
+ const headers = createHeaders({ [FOLDER_KEY]: options.folderKey });
3892
+ const response = await this.get(DATA_FABRIC_ENDPOINTS.ROLES.GET_ALL, { params, headers });
3893
+ return validateRolesResponse(response.data);
3894
+ }
3895
+ }
3896
+ __decorate([
3897
+ track('DataFabricRoles.GetAll')
3898
+ ], DataFabricRoleService.prototype, "getAll", null);
3899
+
3900
+ /**
3901
+ * @internal
3902
+ */
3903
+ var DataFabricDirectoryEntityType;
3904
+ (function (DataFabricDirectoryEntityType) {
3905
+ /** Identity user, robot user, or directory robot principal. */
3906
+ DataFabricDirectoryEntityType[DataFabricDirectoryEntityType["User"] = 0] = "User";
3907
+ /** Identity group principal. */
3908
+ DataFabricDirectoryEntityType[DataFabricDirectoryEntityType["Group"] = 1] = "Group";
3909
+ /** External application principal. */
3910
+ DataFabricDirectoryEntityType[DataFabricDirectoryEntityType["Application"] = 2] = "Application";
3911
+ })(DataFabricDirectoryEntityType || (DataFabricDirectoryEntityType = {}));
3912
+ /**
3913
+ * @internal
3914
+ */
3915
+ var DataFabricDirectoryEntityTypeName;
3916
+ (function (DataFabricDirectoryEntityTypeName) {
3917
+ DataFabricDirectoryEntityTypeName["User"] = "User";
3918
+ DataFabricDirectoryEntityTypeName["Group"] = "Group";
3919
+ DataFabricDirectoryEntityTypeName["Application"] = "Application";
3920
+ })(DataFabricDirectoryEntityTypeName || (DataFabricDirectoryEntityTypeName = {}));
3921
+
3922
+ const DEFAULT_DIRECTORY_PAGE_SIZE = 100;
3923
+ const MAX_DIRECTORY_PAGE_SIZE = 100;
3924
+ function validateDirectoryListResponse(data) {
3925
+ if (data === null || typeof data !== 'object' || Array.isArray(data)) {
3926
+ throw new ServerError({
3927
+ message: 'Invalid Data Fabric directory response format.',
3928
+ });
3929
+ }
3930
+ const response = data;
3931
+ if (typeof response.totalCount !== 'number' || !Array.isArray(response.results)) {
3932
+ throw new ServerError({
3933
+ message: 'Invalid Data Fabric directory response format.',
3934
+ });
3935
+ }
3936
+ return {
3937
+ totalCount: response.totalCount,
3938
+ results: response.results,
3939
+ };
3940
+ }
3941
+ function isRecord(value) {
3942
+ return value !== null && typeof value === 'object' && !Array.isArray(value);
3943
+ }
3944
+ function isDirectoryEntityTypeName(value) {
3945
+ return value === DataFabricDirectoryEntityTypeName.User ||
3946
+ value === DataFabricDirectoryEntityTypeName.Group ||
3947
+ value === DataFabricDirectoryEntityTypeName.Application;
3948
+ }
3949
+ function isDirectoryRole(value) {
3950
+ if (!isRecord(value)) {
3951
+ return false;
3952
+ }
3953
+ return typeof value.id === 'string' && typeof value.name === 'string';
3954
+ }
3955
+ function normalizeDirectoryEntry(entry) {
3956
+ if (!isRecord(entry) ||
3957
+ typeof entry.externalId !== 'string' ||
3958
+ typeof entry.name !== 'string' ||
3959
+ !isDirectoryEntityTypeName(entry.type) ||
3960
+ (entry.email !== undefined && entry.email !== null && typeof entry.email !== 'string') ||
3961
+ (entry.objectType !== undefined && entry.objectType !== null && typeof entry.objectType !== 'string') ||
3962
+ (entry.isUIEnabled !== undefined && typeof entry.isUIEnabled !== 'boolean') ||
3963
+ (entry.roles !== undefined && entry.roles !== null && (!Array.isArray(entry.roles) || !entry.roles.every(isDirectoryRole)))) {
3964
+ throw new ServerError({
3965
+ message: 'Invalid Data Fabric directory entry response format.',
3966
+ });
3967
+ }
3968
+ const normalized = {
3969
+ externalId: entry.externalId,
3970
+ name: entry.name,
3971
+ type: entry.type,
3972
+ roles: entry.roles ?? [],
3973
+ isUIEnabled: entry.isUIEnabled ?? true,
3974
+ };
3975
+ if (entry.email !== undefined) {
3976
+ normalized.email = entry.email;
3977
+ }
3978
+ if (entry.objectType !== undefined) {
3979
+ normalized.objectType = entry.objectType;
3980
+ }
3981
+ return normalized;
3982
+ }
3983
+ function normalizePrincipalIds(principalIds) {
3984
+ const ids = Array.isArray(principalIds) ? principalIds : [principalIds];
3985
+ return [...new Set(ids.map(id => id.trim()).filter(Boolean))];
3986
+ }
3987
+ function normalizeRoleIds(roleIds) {
3988
+ return [...new Set(roleIds.map(id => id.trim()).filter(Boolean))];
3989
+ }
3990
+ function normalizePrincipalType(type) {
3991
+ if (typeof type === 'number') {
3992
+ if (type === DataFabricDirectoryEntityType.User ||
3993
+ type === DataFabricDirectoryEntityType.Group ||
3994
+ type === DataFabricDirectoryEntityType.Application) {
3995
+ return type;
3996
+ }
3997
+ throw new ValidationError({
3998
+ message: 'Invalid Data Fabric principal type.',
3999
+ });
4000
+ }
4001
+ switch (type) {
4002
+ case DataFabricDirectoryEntityTypeName.User:
4003
+ return DataFabricDirectoryEntityType.User;
4004
+ case DataFabricDirectoryEntityTypeName.Group:
4005
+ return DataFabricDirectoryEntityType.Group;
4006
+ case DataFabricDirectoryEntityTypeName.Application:
4007
+ return DataFabricDirectoryEntityType.Application;
4008
+ default:
4009
+ throw new ValidationError({
4010
+ message: 'Invalid Data Fabric principal type.',
4011
+ });
4012
+ }
4013
+ }
4014
+ function roleIdsFromEntry(entry) {
4015
+ if (!entry) {
4016
+ return [];
4017
+ }
4018
+ return normalizeRoleIds(entry.roles.map(role => role.id));
4019
+ }
4020
+ function clampDirectoryPageSize(pageSize) {
4021
+ return Math.max(1, Math.min(pageSize ?? DEFAULT_DIRECTORY_PAGE_SIZE, MAX_DIRECTORY_PAGE_SIZE));
4022
+ }
4023
+ /**
4024
+ * @internal
4025
+ */
4026
+ class DataFabricDirectoryService extends BaseService {
4027
+ async fetchAllEntries(options = {}) {
4028
+ const top = clampDirectoryPageSize(options.pageSize);
4029
+ const entries = [];
4030
+ let skip = 0;
4031
+ while (true) {
4032
+ const page = await this.list(skip === 0 ? { top } : { top, skip });
4033
+ entries.push(...page.results);
4034
+ if (page.results.length < top || (page.totalCount !== undefined && entries.length >= page.totalCount)) {
4035
+ return entries;
4036
+ }
4037
+ skip += top;
4038
+ }
4039
+ }
4040
+ /**
4041
+ * Lists one page of Data Fabric directory principals and their current roles.
4042
+ *
4043
+ * Returns directory entries with external IDs, principal metadata, and
4044
+ * assigned Data Fabric roles.
4045
+ *
4046
+ * @param options - Optional offset paging options
4047
+ * @returns Promise resolving to {@link DataFabricDirectoryListResponse}
4048
+ *
4049
+ * @example
4050
+ * ```typescript
4051
+ * import { DataFabricDirectoryService } from '@uipath/uipath-typescript/entities';
4052
+ *
4053
+ * const directory = new DataFabricDirectoryService(sdk);
4054
+ * const page = await directory.list({ skip: 0, top: 50 });
4055
+ * const firstPrincipal = page.results[0];
4056
+ * ```
4057
+ *
4058
+ * @internal
4059
+ */
4060
+ async list(options = {}) {
4061
+ const params = createParams({
4062
+ skip: options.skip,
4063
+ top: clampDirectoryPageSize(options.top),
4064
+ });
4065
+ const response = await this.get(DATA_FABRIC_ENDPOINTS.DIRECTORY.GET_ALL, { params });
4066
+ const data = validateDirectoryListResponse(response.data);
4067
+ const results = data.results.map(normalizeDirectoryEntry);
4068
+ return {
4069
+ totalCount: data.totalCount,
4070
+ results,
4071
+ };
4072
+ }
4073
+ /**
4074
+ * Lists all Data Fabric directory principals and their current roles.
4075
+ *
4076
+ * Follows the Data Fabric directory top/skip pagination and returns
4077
+ * normalized entries. Entries without assigned roles include an empty
4078
+ * `roles` array.
4079
+ *
4080
+ * @param options - Optional page-size options
4081
+ * @returns Promise resolving to an array of {@link DataFabricDirectoryEntry}
4082
+ *
4083
+ * @example
4084
+ * ```typescript
4085
+ * import { DataFabricDirectoryService } from '@uipath/uipath-typescript/entities';
4086
+ *
4087
+ * const directory = new DataFabricDirectoryService(sdk);
4088
+ * const principals = await directory.getAll({ pageSize: 100 });
4089
+ * ```
4090
+ *
4091
+ * @internal
4092
+ */
4093
+ async getAll(options = {}) {
4094
+ return this.fetchAllEntries(options);
4095
+ }
4096
+ /**
4097
+ * Assigns Data Fabric roles to one or more principals.
4098
+ *
4099
+ * The Data Fabric API replaces the role set for each principal, so this
4100
+ * method preserves existing roles by default and posts the union of current
4101
+ * and requested role IDs.
4102
+ *
4103
+ * Role IDs can be discovered with `DataFabricRoleService.getAll()`. Set
4104
+ * `preserveExisting: false` only when intentionally replacing a principal's
4105
+ * Data Fabric role set.
4106
+ *
4107
+ * @param principalIds - Principal external ID or IDs
4108
+ * @param principalType - Principal type
4109
+ * @param roleIds - Data Fabric role IDs to assign
4110
+ * @param options - Optional assignment behavior
4111
+ * @returns Promise resolving to an array of {@link DataFabricDirectoryAssignmentResult}
4112
+ *
4113
+ * @example
4114
+ * ```typescript
4115
+ * import { DataFabricDirectoryEntityTypeName, DataFabricDirectoryService, DataFabricRoleService } from '@uipath/uipath-typescript/entities';
4116
+ *
4117
+ * const roles = new DataFabricRoleService(sdk);
4118
+ * const directory = new DataFabricDirectoryService(sdk);
4119
+ *
4120
+ * const dataWriter = (await roles.getAll()).find(role => role.name === 'DataWriter');
4121
+ * if (!dataWriter) {
4122
+ * throw new Error('DataWriter role not found');
4123
+ * }
4124
+ *
4125
+ * await directory.assignRoles('<identity-group-id>', DataFabricDirectoryEntityTypeName.Group, [dataWriter.id]);
4126
+ * ```
4127
+ *
4128
+ * @example
4129
+ * ```typescript
4130
+ * await directory.assignRoles('<identity-user-id>', DataFabricDirectoryEntityTypeName.User, ['<role-id>'], {
4131
+ * preserveExisting: false,
4132
+ * });
4133
+ * ```
4134
+ *
4135
+ * @internal
4136
+ */
4137
+ async assignRoles(principalIds, principalType, roleIds, options = {}) {
4138
+ const normalizedPrincipalIds = normalizePrincipalIds(principalIds);
4139
+ const normalizedRoleIds = normalizeRoleIds(roleIds);
4140
+ if (normalizedPrincipalIds.length === 0) {
4141
+ throw new ValidationError({ message: 'At least one principal ID is required.' });
4142
+ }
4143
+ if (normalizedRoleIds.length === 0) {
4144
+ throw new ValidationError({ message: 'At least one Data Fabric role ID is required.' });
4145
+ }
4146
+ const type = normalizePrincipalType(principalType);
4147
+ const preserveExisting = options.preserveExisting ?? true;
4148
+ const existingById = new Map();
4149
+ if (preserveExisting) {
4150
+ for (const entry of await this.fetchAllEntries()) {
4151
+ existingById.set(entry.externalId.toLowerCase(), entry);
4152
+ }
4153
+ }
4154
+ return Promise.all(normalizedPrincipalIds.map(async (principalId) => {
4155
+ const existing = existingById.get(principalId.toLowerCase());
4156
+ const mergedRoleIds = preserveExisting
4157
+ ? normalizeRoleIds([...roleIdsFromEntry(existing), ...normalizedRoleIds])
4158
+ : normalizedRoleIds;
4159
+ const payload = {
4160
+ directoryEntities: [
4161
+ {
4162
+ externalId: principalId,
4163
+ type,
4164
+ resolved: true,
4165
+ },
4166
+ ],
4167
+ roles: mergedRoleIds,
4168
+ isUIEnabled: options.uiEnabled ?? true,
4169
+ };
4170
+ await this.post(DATA_FABRIC_ENDPOINTS.DIRECTORY.ASSIGN_ROLES, payload);
4171
+ return {
4172
+ principalId,
4173
+ roleIds: mergedRoleIds,
4174
+ };
4175
+ }));
4176
+ }
4177
+ /**
4178
+ * Revokes all direct Data Fabric roles from one or more principals.
4179
+ *
4180
+ * The Data Fabric API removes all role assignments for each supplied external
4181
+ * ID. Use this when a principal should no longer have direct Data Fabric
4182
+ * access. Inherited access through groups is not changed.
4183
+ *
4184
+ * @param principalIds - Principal external ID or IDs
4185
+ * @returns Promise resolving when the roles are revoked
4186
+ *
4187
+ * @example
4188
+ * ```typescript
4189
+ * import { DataFabricDirectoryService } from '@uipath/uipath-typescript/entities';
4190
+ *
4191
+ * const directory = new DataFabricDirectoryService(sdk);
4192
+ *
4193
+ * await directory.revokeRoles('<identity-user-id>');
4194
+ * ```
4195
+ *
4196
+ * @example
4197
+ * ```typescript
4198
+ * await directory.revokeRoles([
4199
+ * '<identity-user-id>',
4200
+ * '<identity-group-id>',
4201
+ * ]);
4202
+ * ```
4203
+ *
4204
+ * @internal
4205
+ */
4206
+ async revokeRoles(principalIds) {
4207
+ const normalizedPrincipalIds = normalizePrincipalIds(principalIds);
4208
+ if (normalizedPrincipalIds.length === 0) {
4209
+ throw new ValidationError({ message: 'At least one principal ID is required.' });
4210
+ }
4211
+ const payload = {
4212
+ externalIds: normalizedPrincipalIds,
4213
+ };
4214
+ await this.post(DATA_FABRIC_ENDPOINTS.DIRECTORY.REVOKE_ROLES, payload);
4215
+ }
4216
+ }
4217
+ __decorate([
4218
+ track('DataFabricDirectory.List')
4219
+ ], DataFabricDirectoryService.prototype, "list", null);
4220
+ __decorate([
4221
+ track('DataFabricDirectory.GetAll')
4222
+ ], DataFabricDirectoryService.prototype, "getAll", null);
4223
+ __decorate([
4224
+ track('DataFabricDirectory.AssignRoles')
4225
+ ], DataFabricDirectoryService.prototype, "assignRoles", null);
4226
+ __decorate([
4227
+ track('DataFabricDirectory.RevokeRoles')
4228
+ ], DataFabricDirectoryService.prototype, "revokeRoles", null);
4229
+
4230
+ export { ChoiceSetService, ChoiceSetService as ChoiceSets, DataDirectionType, DataFabricDirectoryService, DataFabricRoleService, EntityService as Entities, EntityAggregateFunction, EntityFieldDataType, EntityService, EntityType, FieldDisplayType, JoinType, LogicalOperator, QueryFilterOperator, ReferenceType, createEntityWithMethods };
@@ -966,7 +966,16 @@ const BUCKET_TOKEN_PARAMS = {
966
966
  * Returns the original value if parsing fails.
967
967
  */
968
968
  /**
969
- * Transforms data by mapping fields according to the provided field mapping
969
+ * Transforms data by renaming each key in `data` exactly once, using the
970
+ * mapping (`sourceField → targetField`). Keys not present in the mapping
971
+ * pass through unchanged. The original (pre-rename) key is dropped — the
972
+ * result contains only the renamed key.
973
+ *
974
+ * Each rename is independent. If the mapping happens to contain chained
975
+ * entries (`a → b` and `b → c`), they do NOT compose: a field named `a`
976
+ * in `data` becomes `b` (not `c`), because the renames are applied based
977
+ * on the original data's keys, not the running result.
978
+ *
970
979
  * @param data The source data to transform
971
980
  * @param fieldMapping Object mapping source field names to target field names
972
981
  * @returns Transformed data with mapped field names
@@ -989,21 +998,28 @@ const BUCKET_TOKEN_PARAMS = {
989
998
  * // { userId: '123', name: 'john' },
990
999
  * // { userId: '456', name: 'jane' }
991
1000
  * // ]
1001
+ *
1002
+ * // No chaining — `a → b` does not become `a → c` even if the map has `b → c`.
1003
+ * transformData({ a: 1 }, { a: 'b', b: 'c' });
1004
+ * // result = { b: 1 }
992
1005
  * ```
993
1006
  */
994
1007
  function transformData(data, fieldMapping) {
1008
+ // Pass null/undefined through unchanged — callers (e.g. AttachmentService.getById)
1009
+ // may invoke this on optional fields that an OData `select` excluded.
1010
+ if (data == null) {
1011
+ return data;
1012
+ }
995
1013
  // Handle array of objects
996
1014
  if (Array.isArray(data)) {
997
1015
  return data.map(item => transformData(item, fieldMapping));
998
1016
  }
999
- // Handle single object
1000
- const result = { ...data };
1001
- for (const [sourceField, targetField] of Object.entries(fieldMapping)) {
1002
- if (sourceField in result) {
1003
- const value = result[sourceField];
1004
- delete result[sourceField];
1005
- result[targetField] = value;
1006
- }
1017
+ // Walk the ORIGINAL data's keys, look up each in the mapping. One rename
1018
+ // per data key — no mutation of an in-progress result, so chains can't form.
1019
+ const result = {};
1020
+ for (const [key, value] of Object.entries(data)) {
1021
+ const renamedKey = fieldMapping[key] ?? key;
1022
+ result[renamedKey] = value;
1007
1023
  }
1008
1024
  return result;
1009
1025
  }
@@ -964,7 +964,16 @@ const BUCKET_TOKEN_PARAMS = {
964
964
  * Returns the original value if parsing fails.
965
965
  */
966
966
  /**
967
- * Transforms data by mapping fields according to the provided field mapping
967
+ * Transforms data by renaming each key in `data` exactly once, using the
968
+ * mapping (`sourceField → targetField`). Keys not present in the mapping
969
+ * pass through unchanged. The original (pre-rename) key is dropped — the
970
+ * result contains only the renamed key.
971
+ *
972
+ * Each rename is independent. If the mapping happens to contain chained
973
+ * entries (`a → b` and `b → c`), they do NOT compose: a field named `a`
974
+ * in `data` becomes `b` (not `c`), because the renames are applied based
975
+ * on the original data's keys, not the running result.
976
+ *
968
977
  * @param data The source data to transform
969
978
  * @param fieldMapping Object mapping source field names to target field names
970
979
  * @returns Transformed data with mapped field names
@@ -987,21 +996,28 @@ const BUCKET_TOKEN_PARAMS = {
987
996
  * // { userId: '123', name: 'john' },
988
997
  * // { userId: '456', name: 'jane' }
989
998
  * // ]
999
+ *
1000
+ * // No chaining — `a → b` does not become `a → c` even if the map has `b → c`.
1001
+ * transformData({ a: 1 }, { a: 'b', b: 'c' });
1002
+ * // result = { b: 1 }
990
1003
  * ```
991
1004
  */
992
1005
  function transformData(data, fieldMapping) {
1006
+ // Pass null/undefined through unchanged — callers (e.g. AttachmentService.getById)
1007
+ // may invoke this on optional fields that an OData `select` excluded.
1008
+ if (data == null) {
1009
+ return data;
1010
+ }
993
1011
  // Handle array of objects
994
1012
  if (Array.isArray(data)) {
995
1013
  return data.map(item => transformData(item, fieldMapping));
996
1014
  }
997
- // Handle single object
998
- const result = { ...data };
999
- for (const [sourceField, targetField] of Object.entries(fieldMapping)) {
1000
- if (sourceField in result) {
1001
- const value = result[sourceField];
1002
- delete result[sourceField];
1003
- result[targetField] = value;
1004
- }
1015
+ // Walk the ORIGINAL data's keys, look up each in the mapping. One rename
1016
+ // per data key — no mutation of an in-progress result, so chains can't form.
1017
+ const result = {};
1018
+ for (const [key, value] of Object.entries(data)) {
1019
+ const renamedKey = fieldMapping[key] ?? key;
1020
+ result[renamedKey] = value;
1005
1021
  }
1006
1022
  return result;
1007
1023
  }