@zimbra/api-client 99.0.0 → 100.1.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.
Files changed (36) hide show
  1. package/.babelrc.json +1 -2
  2. package/dist/schema.graphql +10 -2
  3. package/dist/src/apollo/local-batch-link.d.ts +0 -1
  4. package/dist/src/apollo/offline-queue-link/index.d.ts +1 -4
  5. package/dist/src/batch-client/index.d.ts +4 -1
  6. package/dist/src/batch-client/types.d.ts +1 -1
  7. package/dist/src/normalize/entities.d.ts +1 -0
  8. package/dist/src/normalize/index.d.ts +1 -1
  9. package/dist/src/request/types.d.ts +0 -1
  10. package/dist/src/schema/generated-schema-types.d.ts +13 -2
  11. package/dist/src/utils/map-values-deep.d.ts +1 -0
  12. package/dist/zm-api-js-client.esm.js +210 -157
  13. package/dist/zm-api-js-client.esm.js.map +1 -1
  14. package/dist/zm-api-js-client.js +8 -8
  15. package/dist/zm-api-js-client.js.map +1 -1
  16. package/dist/zm-api-js-client.umd.js +8 -8
  17. package/dist/zm-api-js-client.umd.js.map +1 -1
  18. package/package-lock.json +339 -178
  19. package/package.json +3 -3
  20. package/rollup.config.js +1 -1
  21. package/src/apollo/offline-queue-link/util.ts +1 -2
  22. package/src/apollo/zimbra-error-link.ts +4 -3
  23. package/src/apollo/zimbra-in-memory-cache.ts +3 -3
  24. package/src/batch-client/index.ts +81 -47
  25. package/src/batch-client/types.ts +1 -1
  26. package/src/normalize/entities.ts +6 -1
  27. package/src/normalize/index.ts +42 -39
  28. package/src/request/index.ts +36 -48
  29. package/src/request/types.ts +0 -1
  30. package/src/schema/generated-schema-types.ts +15 -2
  31. package/src/schema/schema.graphql +10 -2
  32. package/src/schema/schema.ts +3 -2
  33. package/src/schema/session-handler.ts +1 -2
  34. package/src/utils/map-values-deep.ts +10 -2
  35. package/src/utils/normalize-attrs-custommetadata.ts +5 -6
  36. package/src/utils/normalize-otherAttribute-contact.ts +29 -19
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zimbra/api-client",
3
3
  "amdName": "zmApiJsClient",
4
- "version": "99.0.0",
4
+ "version": "100.1.0",
5
5
  "description": "Zimbra JS API Client and GraphQL client for making requests against the Zimbra SOAP API.",
6
6
  "main": "dist/zm-api-js-client.js",
7
7
  "source": "index.ts",
@@ -47,11 +47,11 @@
47
47
  ]
48
48
  },
49
49
  "dependencies": {
50
- "@apollo/client": "3.4.16",
50
+ "@apollo/client": "^3.14.0",
51
51
  "@graphql-tools/schema": "^10.0.25",
52
52
  "dataloader": "^2.2.2",
53
+ "es-toolkit": "^1.39.10",
53
54
  "graphql": "^16.9.0",
54
- "lodash": "^4.17.21",
55
55
  "mitt": "^3.0.0"
56
56
  },
57
57
  "devDependencies": {
package/rollup.config.js CHANGED
@@ -11,7 +11,7 @@ const FORMAT = process.env.FORMAT;
11
11
  const externalDeps = [
12
12
  '@apollo/client',
13
13
  'graphql',
14
- 'lodash',
14
+ 'es-toolkit',
15
15
  'mitt'
16
16
  ];
17
17
 
@@ -1,9 +1,8 @@
1
1
  import { Operation } from '@apollo/client/core';
2
- import get from 'lodash/get';
3
2
  import { OfflineOperationEntry, OperationEntry } from './types';
4
3
 
5
4
  export function hasSensitiveVariables(operation: Operation) {
6
- return !!get(operation, 'variables.password');
5
+ return !!operation?.variables?.password;
7
6
  }
8
7
 
9
8
  export function isMutationOperation({ query }: Operation) {
@@ -1,5 +1,4 @@
1
1
  import { ErrorLink } from '@apollo/client/link/error';
2
- import get from 'lodash/get';
3
2
 
4
3
  class ZimbraErrorLink extends ErrorLink {
5
4
  handlers: any[] = [];
@@ -7,8 +6,10 @@ class ZimbraErrorLink extends ErrorLink {
7
6
  constructor() {
8
7
  super(({ graphQLErrors, networkError }) => {
9
8
  graphQLErrors &&
10
- graphQLErrors.map(({ message, originalError, ...rest }) => {
11
- let errorCode = get(originalError, 'faults.0.Detail.Error.Code', '');
9
+ graphQLErrors.map((error: any) => {
10
+ const { message, ...rest } = error;
11
+ const originalError = error.originalError;
12
+ const errorCode = (originalError as any)?.faults?.[0]?.Detail?.Error?.Code || '';
12
13
 
13
14
  this.executeHandlers({
14
15
  errorCode,
@@ -1,12 +1,12 @@
1
1
  import { FieldFunctionOptions } from '@apollo/client';
2
2
  import { defaultDataIdFromObject, InMemoryCache, InMemoryCacheConfig } from '@apollo/client/core';
3
- import get from 'lodash/get';
4
- import uniqWith from 'lodash/uniqWith';
3
+ import { uniqWith } from 'es-toolkit';
4
+ import { getValueByPath } from '../utils/map-values-deep';
5
5
  import { EmailAddress } from './types';
6
6
 
7
7
  const dataIdFromPath = (result: any, path: string) => {
8
8
  if (result.__typename) {
9
- const id = get(result, path);
9
+ const id = getValueByPath(result, path);
10
10
  return id ? `${result.__typename}:${id}` : defaultDataIdFromObject(result);
11
11
  }
12
12
  };
@@ -1,8 +1,5 @@
1
1
  import DataLoader from 'dataloader';
2
- import castArray from 'lodash/castArray';
3
- import get from 'lodash/get';
4
- import isError from 'lodash/isError';
5
- import mapValues from 'lodash/mapValues';
2
+ import { mapValues } from 'es-toolkit';
6
3
  import { denormalize, normalize } from '../normalize';
7
4
  import {
8
5
  AccountRights,
@@ -35,6 +32,7 @@ import {
35
32
  GetDocumentShareURLEntity,
36
33
  GetDocumentShareURLResponseEntity,
37
34
  GetFolderRequest as GetFolderRequestEntity,
35
+ GetItem,
38
36
  GetRightsRequest,
39
37
  HabGroup,
40
38
  InviteReply,
@@ -75,6 +73,7 @@ import {
75
73
  ExternalAccountImportInput,
76
74
  ExternalAccountTestInput,
77
75
  FilterInput,
76
+ FilterMatchCondition,
78
77
  FolderActionChangeColorInput,
79
78
  FolderActionCheckCalendarInput,
80
79
  FolderView,
@@ -186,7 +185,7 @@ function normalizeMessage(
186
185
  }
187
186
 
188
187
  const hasUnreadDescendent = (folder: any): any => {
189
- const unreadDescendent = get(folder, 'unreadDescendent');
188
+ const unreadDescendent = folder?.unreadDescendent;
190
189
 
191
190
  if (
192
191
  folder[
@@ -199,7 +198,7 @@ const hasUnreadDescendent = (folder: any): any => {
199
198
  return true;
200
199
  }
201
200
 
202
- const folderArray = get(folder, 'folders') || [];
201
+ const folderArray = folder?.folders || [];
203
202
  for (let i = 0, len = folderArray.length; i < len; i++) {
204
203
  return hasUnreadDescendent(folderArray[i]);
205
204
  }
@@ -209,7 +208,7 @@ const hasUnreadDescendent = (folder: any): any => {
209
208
 
210
209
  const updateGroupName = (habGroup: any) => ({
211
210
  ...habGroup,
212
- name: get(habGroup, 'attributes.displayName')
211
+ name: habGroup?.attributes?.displayName
213
212
  });
214
213
 
215
214
  const updateGroupNameRecur = (habGroups: any) =>
@@ -220,8 +219,8 @@ const updateGroupNameRecur = (habGroups: any) =>
220
219
  });
221
220
 
222
221
  const setUnreadDescendentFlag = (folder: any) => {
223
- const folderArray = get(folder, 'folders') || [];
224
- const view = get(folder, 'view');
222
+ const folderArray = folder?.folders || [];
223
+ const view = folder?.view;
225
224
 
226
225
  // setting this flag only in message view has we dont want to show unread count in
227
226
  // other views
@@ -406,7 +405,7 @@ export class ZimbraBatchClient {
406
405
  [<string>accountType]: mapValuesDeep(accountInfo, coerceBooleanToString)
407
406
  },
408
407
  singleRequest: true
409
- }).then(res => get(res, `${accountType}.0.id`));
408
+ }).then(res => res?.[<string>accountType]?.[0]?.id);
410
409
 
411
410
  public addMessage = (message: AddMsgInput) => {
412
411
  const { folderId, content, meta } = message;
@@ -457,7 +456,7 @@ export class ZimbraBatchClient {
457
456
  }
458
457
  }
459
458
  }).then(res => {
460
- const ids = get(res, 'm[0].ids');
459
+ const ids = res?.m?.[0]?.ids;
461
460
  return ids ? ids.split(',') : [];
462
461
  });
463
462
 
@@ -532,8 +531,7 @@ export class ZimbraBatchClient {
532
531
  password,
533
532
  username,
534
533
  dryRun = false,
535
- authToken,
536
- csrfToken
534
+ authToken
537
535
  }: ChangePasswordOptions) => {
538
536
  if (authToken) {
539
537
  return this.jsonRequest({
@@ -547,8 +545,7 @@ export class ZimbraBatchClient {
547
545
  oldPassword: password,
548
546
  password: loginNewPassword,
549
547
  dryRun,
550
- authToken: { _content: authToken },
551
- csrfToken: { _content: csrfToken }
548
+ authToken: { _content: authToken }
552
549
  },
553
550
  singleRequest: true
554
551
  });
@@ -676,13 +673,11 @@ export class ZimbraBatchClient {
676
673
  identity: {
677
674
  ...rest,
678
675
  _attrs: {
679
- ...mapValues(attrs, coerceBooleanToString),
676
+ ...mapValues(attrs || {}, coerceBooleanToString),
680
677
  zimbraPrefWhenSentToAddresses: convertStringAndArrayValues(
681
- get(attrs, 'zimbraPrefWhenSentToAddresses')
678
+ attrs?.zimbraPrefWhenSentToAddresses
682
679
  ),
683
- zimbraPrefWhenInFolderIds: convertStringAndArrayValues(
684
- get(attrs, 'zimbraPrefWhenInFolderIds')
685
- )
680
+ zimbraPrefWhenInFolderIds: convertStringAndArrayValues(attrs?.zimbraPrefWhenInFolderIds)
686
681
  }
687
682
  }
688
683
  },
@@ -692,7 +687,7 @@ export class ZimbraBatchClient {
692
687
  const {
693
688
  _attrs: { zimbraPrefWhenSentToAddresses, zimbraPrefWhenInFolderIds, ...restAttr },
694
689
  ...restIdentityProps
695
- } = get(mappedResult, 'identity.0');
690
+ } = mappedResult?.identity?.[0];
696
691
 
697
692
  return {
698
693
  ...mappedResult,
@@ -942,7 +937,6 @@ export class ZimbraBatchClient {
942
937
  Header: {
943
938
  context: {
944
939
  _jsns: Namespace.All,
945
- csrfToken: this.csrfToken,
946
940
  account: {
947
941
  by: 'name',
948
942
  _content: options.accountName
@@ -957,11 +951,15 @@ export class ZimbraBatchClient {
957
951
  };
958
952
 
959
953
  try {
960
- const blob = new Blob([JSON.stringify(body)]);
961
- if (navigator) {
962
- // In zimbra desktop client navigator is null
963
- navigator.sendBeacon(`${this.origin}/service/soap`, blob);
964
- }
954
+ fetch(`${this.origin}/service/soap`, {
955
+ method: 'POST',
956
+ keepalive: true,
957
+ headers: {
958
+ 'Content-Type': 'application/json',
959
+ 'X-Zimbra-Csrf-Token': this.csrfToken || ''
960
+ },
961
+ body: JSON.stringify(body)
962
+ });
965
963
  } catch (e) {
966
964
  throw new Error('Error on endSessionBeaconRequest request' + e);
967
965
  }
@@ -1074,7 +1072,7 @@ export class ZimbraBatchClient {
1074
1072
  this.jsonRequest({
1075
1073
  name: 'GetConv',
1076
1074
  body: {
1077
- c: mapValues(options, coerceBooleanToInt)
1075
+ c: mapValues(options || {}, coerceBooleanToInt)
1078
1076
  }
1079
1077
  }).then(res => {
1080
1078
  const conversation = this.normalizeConversation(res.c[0]);
@@ -1115,7 +1113,7 @@ export class ZimbraBatchClient {
1115
1113
  this.jsonRequest({
1116
1114
  name: 'GetDeviceStatus',
1117
1115
  namespace: Namespace.Sync
1118
- }).then(res => get(res, 'device') || []);
1116
+ }).then(res => res?.device || []);
1119
1117
 
1120
1118
  public getDistributionList = (dl: String, needOwners: Boolean, needRights: String, by: String) =>
1121
1119
  this.jsonRequest({
@@ -1166,7 +1164,24 @@ export class ZimbraBatchClient {
1166
1164
  public getFilterRules = () =>
1167
1165
  this.jsonRequest({
1168
1166
  name: 'GetFilterRules'
1169
- }).then(res => normalize(Filter)(get(res, 'filterRules.0.filterRule') || []));
1167
+ }).then(res => {
1168
+ const filterRules = res?.filterRules?.[0]?.filterRule || [];
1169
+
1170
+ // Set default condition to anyof in case of null or undefined :: Classic UI approach
1171
+ for (let i = 0; i < filterRules.length; i++) {
1172
+ const rule = filterRules[i];
1173
+ if (rule?.filterTests && Array.isArray(rule.filterTests)) {
1174
+ for (let j = 0; j < rule.filterTests.length; j++) {
1175
+ const test = rule?.filterTests[j];
1176
+ if (test?.condition === null || test?.condition === undefined) {
1177
+ test.condition = FilterMatchCondition.Anyof;
1178
+ }
1179
+ }
1180
+ }
1181
+ }
1182
+
1183
+ return normalize(Filter)(filterRules);
1184
+ });
1170
1185
 
1171
1186
  public getFolder = (options: GetFolderOptions) => {
1172
1187
  return this.jsonRequest({
@@ -1174,7 +1189,7 @@ export class ZimbraBatchClient {
1174
1189
  body: denormalize(GetFolderRequestEntity)(options)
1175
1190
  }).then(res => {
1176
1191
  const foldersResponse = normalize(Folder)(res);
1177
- const folders = get(foldersResponse, 'folders.0', {});
1192
+ const folders = foldersResponse?.folders?.[0] || {};
1178
1193
 
1179
1194
  if (folders.folders) {
1180
1195
  folders.folders = folders.folders.map(setUnreadDescendentFlag);
@@ -1239,7 +1254,7 @@ export class ZimbraBatchClient {
1239
1254
  },
1240
1255
  namespace: Namespace.Account
1241
1256
  }).then(res => {
1242
- const habGroups = get(res, 'ou.0');
1257
+ const habGroups = res?.ou?.[0] || {};
1243
1258
  return {
1244
1259
  ...habGroups,
1245
1260
  habGroups: [...updateGroupNameRecur(habGroups.habGroup)]
@@ -1281,6 +1296,22 @@ export class ZimbraBatchClient {
1281
1296
  name: 'GetImportStatus'
1282
1297
  });
1283
1298
 
1299
+ public getItem = ({ id }: any) =>
1300
+ this.jsonRequest({
1301
+ name: 'GetItem',
1302
+ namespace: Namespace.Mail,
1303
+ body: {
1304
+ item: {
1305
+ id
1306
+ }
1307
+ }
1308
+ }).then(response => {
1309
+ const data = normalize(GetItem)(response);
1310
+ return {
1311
+ docs: data.documents
1312
+ };
1313
+ });
1314
+
1284
1315
  public getMailboxMetadata = ({ section }: GetMailboxMetadataOptions) =>
1285
1316
  this.jsonRequest({
1286
1317
  name: 'GetMailboxMetadata',
@@ -1346,7 +1377,12 @@ export class ZimbraBatchClient {
1346
1377
 
1347
1378
  for (const pref in prefs) {
1348
1379
  if (CASTING_PREFS.indexOf(pref) !== -1) {
1349
- prefs[pref] = typeof prefs[pref] === 'string' ? castArray(prefs[pref]) : prefs[pref];
1380
+ prefs[pref] =
1381
+ typeof prefs[pref] === 'string'
1382
+ ? prefs[pref] !== undefined
1383
+ ? [prefs[pref]]
1384
+ : []
1385
+ : prefs[pref];
1350
1386
  }
1351
1387
  }
1352
1388
  return prefs;
@@ -1607,13 +1643,11 @@ export class ZimbraBatchClient {
1607
1643
  identity: {
1608
1644
  ...rest,
1609
1645
  _attrs: {
1610
- ...mapValues(attrs, coerceBooleanToString),
1646
+ ...mapValues(attrs || {}, coerceBooleanToString),
1611
1647
  zimbraPrefWhenSentToAddresses: convertStringAndArrayValues(
1612
- get(attrs, 'zimbraPrefWhenSentToAddresses')
1648
+ attrs?.zimbraPrefWhenSentToAddresses
1613
1649
  ),
1614
- zimbraPrefWhenInFolderIds: convertStringAndArrayValues(
1615
- get(attrs, 'zimbraPrefWhenInFolderIds')
1616
- )
1650
+ zimbraPrefWhenInFolderIds: convertStringAndArrayValues(attrs?.zimbraPrefWhenInFolderIds)
1617
1651
  }
1618
1652
  }
1619
1653
  },
@@ -2037,7 +2071,7 @@ export class ZimbraBatchClient {
2037
2071
  [<string>accountType]: mapValuesDeep(accountInfo, coerceBooleanToString)
2038
2072
  },
2039
2073
  singleRequest: true
2040
- }).then(res => mapValuesDeep(get(res, `${accountType}.0`), coerceStringToBoolean));
2074
+ }).then(res => mapValuesDeep(res?.[<string>accountType]?.[0], coerceStringToBoolean));
2041
2075
 
2042
2076
  public uploadMessage = (message: string): any => {
2043
2077
  const contentDisposition = 'attachment';
@@ -2086,9 +2120,9 @@ export class ZimbraBatchClient {
2086
2120
  requests,
2087
2121
  ...this.getAdditionalRequestOptions()
2088
2122
  }).then(response => {
2089
- const sessionId = get(response, 'header.context.session.id');
2090
- const notifications = get(response, 'header.context.notify.0');
2091
- const refresh = get(response, 'header.context.refresh');
2123
+ const sessionId = response?.header?.context?.session?.id;
2124
+ const notifications = response?.header?.context?.notify?.[0];
2125
+ const refresh = response?.header?.context?.refresh;
2092
2126
 
2093
2127
  this.checkAndUpdateSessionId(sessionId);
2094
2128
 
@@ -2106,7 +2140,7 @@ export class ZimbraBatchClient {
2106
2140
  if (DEBUG) {
2107
2141
  console.log(`[Batch Client Request] ${requests[i].name}`, requests[i].body, r);
2108
2142
  }
2109
- return isError(r) ? r : r.body;
2143
+ return r instanceof Error ? r : r.body;
2110
2144
  });
2111
2145
  });
2112
2146
 
@@ -2124,9 +2158,9 @@ export class ZimbraBatchClient {
2124
2158
  // check if login request then don't add csrfToken
2125
2159
  ...this.getAdditionalRequestOptions(requests[0].name !== 'Auth')
2126
2160
  }).then(response => {
2127
- const sessionId = get(response, 'header.context.session.id');
2128
- const notifications = get(response, 'header.context.notify.0');
2129
- const refresh = get(response, 'header.context.refresh');
2161
+ const sessionId = response?.header?.context?.session?.id;
2162
+ const notifications = response?.header?.context?.notify?.[0];
2163
+ const refresh = response?.header?.context?.refresh;
2130
2164
 
2131
2165
  this.checkAndUpdateSessionId(sessionId);
2132
2166
 
@@ -2140,7 +2174,7 @@ export class ZimbraBatchClient {
2140
2174
  }
2141
2175
  }
2142
2176
 
2143
- return isError(response) ? [response] : [response.body];
2177
+ return response instanceof Error ? [response] : [response.body];
2144
2178
  });
2145
2179
 
2146
2180
  private download = ({ isSecure, url }: any) =>
@@ -178,6 +178,7 @@ export interface AppointmentOptions {
178
178
  }
179
179
 
180
180
  export interface SaveDocumentInput {
181
+ content: string;
181
182
  ct: string;
182
183
  descEnabled: Boolean;
183
184
  id: string;
@@ -234,7 +235,6 @@ export interface ShareInfoOptions {
234
235
 
235
236
  export interface ChangePasswordOptions {
236
237
  authToken: string;
237
- csrfToken: string;
238
238
  dryRun: boolean;
239
239
  loginNewPassword: string;
240
240
  password: string;
@@ -533,6 +533,10 @@ export const ListDocumentRevisions = new Entity({
533
533
  doc: ['documents', Document]
534
534
  });
535
535
 
536
+ export const GetItem = new Entity({
537
+ doc: ['documents', Document]
538
+ });
539
+
536
540
  export const MessagePartInputForDocuments = new Entity({
537
541
  id: 'messageId',
538
542
  part: 'attachmentPart'
@@ -545,7 +549,8 @@ export const SaveDocument = new Entity({
545
549
  ct: 'contentType',
546
550
  descEnabled: 'descriptionEnabled',
547
551
  m: ['messageData', MessagePartInputForDocuments],
548
- doc: ['document', Document]
552
+ doc: ['document', Document],
553
+ content: 'content'
549
554
  });
550
555
 
551
556
  export const SearchResponse = new Entity({
@@ -1,5 +1,3 @@
1
- import reduce from 'lodash/reduce';
2
-
3
1
  import { EntityMapping, EntityMappingValue, NormalizedKey } from './types';
4
2
 
5
3
  function normalizeKey(key: string, schema: Entity, inverse: Boolean = false): NormalizedKey {
@@ -19,25 +17,28 @@ function normalizeKey(key: string, schema: Entity, inverse: Boolean = false): No
19
17
  return { key };
20
18
  }
21
19
 
22
- function _normalize(data: {}, schema: Entity, inverse: Boolean = false) {
23
- return reduce(
24
- data,
25
- (result: { [key: string]: any }, v, k) => {
26
- const { key, nestedSchema } = normalizeKey(k, schema, inverse);
27
- const type = typeof v;
28
- if (Array.isArray(v)) {
29
- result[key] = (v as Array<any>).map(i =>
30
- nestedSchema ? _normalize(i, nestedSchema, inverse) : i
31
- );
32
- } else if (type === 'object' && v !== null) {
33
- result[key] = nestedSchema ? _normalize(v, nestedSchema, inverse) : v;
34
- } else {
35
- result[key] = v;
36
- }
37
- return result;
38
- },
39
- {}
40
- );
20
+ function _normalize(data: {}, schema: Entity, inverse: boolean = false) {
21
+ const result: { [key: string]: any } = {};
22
+
23
+ for (const k in data) {
24
+ if (!Object.prototype.hasOwnProperty.call(data, k)) {
25
+ continue;
26
+ }
27
+
28
+ const v = (data as any)[k];
29
+ const { key, nestedSchema } = normalizeKey(k, schema, inverse);
30
+ const type = typeof v;
31
+
32
+ if (Array.isArray(v)) {
33
+ result[key] = v.map(i => (nestedSchema ? _normalize(i, nestedSchema, inverse) : i));
34
+ } else if (type === 'object' && v !== null) {
35
+ result[key] = nestedSchema ? _normalize(v, nestedSchema, inverse) : v;
36
+ } else {
37
+ result[key] = v;
38
+ }
39
+ }
40
+
41
+ return result;
41
42
  }
42
43
 
43
44
  /**
@@ -74,24 +75,26 @@ export class Entity {
74
75
  this.inverseMapping = this.initInverseMapping(this.mapping);
75
76
  }
76
77
 
77
- initInverseMapping(mapping: EntityMapping, accumulator = {}) {
78
- return reduce(
79
- mapping,
80
- (result: EntityMapping, v: any, k) => {
81
- if (Array.isArray(v)) {
82
- result[v[0]] = [k, v[1]];
83
- } else if (typeof v === 'object' && !(v instanceof Entity)) {
84
- result[k] = this.initInverseMapping(v) as EntityMappingValue;
85
- } else if (typeof v === 'string') {
86
- result[v] = k;
87
- } else {
88
- result[k] = v;
89
- }
90
-
91
- return result;
92
- },
93
- accumulator
94
- );
78
+ initInverseMapping(mapping: EntityMapping, accumulator: EntityMapping = {}): EntityMapping {
79
+ for (const k in mapping) {
80
+ if (!Object.prototype.hasOwnProperty.call(mapping, k)) {
81
+ continue;
82
+ }
83
+
84
+ const v: any = mapping[k];
85
+
86
+ if (Array.isArray(v)) {
87
+ accumulator[v[0]] = [k, v[1]];
88
+ } else if (typeof v === 'object' && !(v instanceof Entity)) {
89
+ accumulator[k] = this.initInverseMapping(v) as EntityMappingValue;
90
+ } else if (typeof v === 'string') {
91
+ accumulator[v] = k;
92
+ } else {
93
+ accumulator[k] = v;
94
+ }
95
+ }
96
+
97
+ return accumulator;
95
98
  }
96
99
 
97
100
  public inverseKey(k: string) {
@@ -1,5 +1,3 @@
1
- import get from 'lodash/get';
2
- import reduce from 'lodash/reduce';
3
1
  import {
4
2
  BatchRequestOptions,
5
3
  BatchRequestResponse,
@@ -39,7 +37,7 @@ function parseJSON(response: Response): Promise<ParsedResponse> {
39
37
  // for the rest of the cases (as of now only 500 error), parse and return the error response so that it can
40
38
  // be handled properly by the caller
41
39
  return parseErrorJSON(response).then(parsedResponse => {
42
- const fault = get(parsedResponse.parsed, 'Body.Fault');
40
+ const fault = parsedResponse?.parsed?.Body?.Fault;
43
41
  throw faultError(parsedResponse, [fault]);
44
42
  });
45
43
  }
@@ -71,7 +69,7 @@ function networkError(response: ParsedResponse) {
71
69
 
72
70
  (error as NetworkError).message = message;
73
71
  (error as NetworkError).response = response;
74
- (error as NetworkError).parseError = response.parseError;
72
+ (error as NetworkError).parseError = response?.parseError;
75
73
 
76
74
  return error as NetworkError;
77
75
  }
@@ -80,7 +78,7 @@ function faultReasonText(faults: any = []): string {
80
78
  if (!Array.isArray(faults)) faults = [faults];
81
79
 
82
80
  return faults
83
- .map((f: any) => get(f, 'Reason.Text'))
81
+ .map((f: any) => f?.Reason?.Text)
84
82
  .filter(Boolean)
85
83
  .join(', ');
86
84
  }
@@ -88,7 +86,7 @@ function faultReasonText(faults: any = []): string {
88
86
  function faultError(response: ParsedResponse, faults: any) {
89
87
  const error = new Error(`Fault error: ${faults ? faultReasonText(faults) : 'Unknown Error'}`);
90
88
  (error as SingleBatchRequestError).response = response;
91
- (error as SingleBatchRequestError).parseError = response.parseError;
89
+ (error as SingleBatchRequestError).parseError = response?.parseError;
92
90
  (error as SingleBatchRequestError).faults = faults;
93
91
  return error as SingleBatchRequestError;
94
92
  }
@@ -98,20 +96,20 @@ function faultError(response: ParsedResponse, faults: any) {
98
96
  * containing an array of the requests for that command.
99
97
  */
100
98
  function batchBody(requests: ReadonlyArray<RequestOptions>) {
101
- return reduce(
102
- requests,
103
- (body: { [key: string]: any }, request) => {
104
- const key = `${request.name}Request`;
105
- const value = soapCommandBody(request);
106
- if (body[key]) {
107
- body[key].push(value);
108
- } else {
109
- body[key] = [value];
110
- }
111
- return body;
112
- },
113
- {}
114
- );
99
+ const body: { [key: string]: any } = {};
100
+
101
+ for (const request of requests) {
102
+ const key = `${request.name}Request`;
103
+ const value = soapCommandBody(request);
104
+
105
+ if (body[key]) {
106
+ body[key].push(value);
107
+ } else {
108
+ body[key] = [value];
109
+ }
110
+ }
111
+
112
+ return body;
115
113
  }
116
114
 
117
115
  /**
@@ -127,34 +125,26 @@ function batchResponse(requests: any, response: RequestResponse) {
127
125
  // For each request type, track which responses have been
128
126
  // pulled out of the batch request body by incrementing
129
127
  // indexes.
130
- let indexes: { [key: string]: number } = {};
128
+ const indexes: { [key: string]: number } = {};
129
+ const responses: Array<SingleBatchRequestResponse | SingleBatchRequestError> = [];
130
+
131
+ for (const request of requests) {
132
+ const batchResponses = batchBody[`${request.name}Response`];
133
+ const index = indexes[request.name] || 0;
134
+ const singleResponse = batchResponses?.[index];
135
+
136
+ if (singleResponse) {
137
+ responses.push({ body: singleResponse });
138
+ } else {
139
+ responses.push(faultError(request.originalResponse, batchBody.Fault));
140
+ }
141
+
142
+ indexes[request.name] = index + 1;
143
+ }
131
144
 
132
145
  return {
133
146
  ...res,
134
- requests: reduce(
135
- requests,
136
- (responses: Array<SingleBatchRequestResponse | SingleBatchRequestError>, request) => {
137
- const batchResponses = batchBody[`${request.name}Response`];
138
- const index = indexes[request.name];
139
- const response: any = batchResponses && batchResponses[index || 0];
140
- if (response) {
141
- responses.push({
142
- body: response
143
- });
144
- } else {
145
- responses.push(faultError(res.originalResponse, batchBody.Fault));
146
- }
147
-
148
- if (index) {
149
- indexes[request.name] += 1;
150
- } else {
151
- indexes[request.name] = 1;
152
- }
153
-
154
- return responses;
155
- },
156
- []
157
- )
147
+ requests: responses
158
148
  };
159
149
  }
160
150
 
@@ -232,8 +222,6 @@ export function jsonRequest(requestOptions: JsonRequestOptions): Promise<Request
232
222
 
233
223
  if (requestOptions.csrfToken) {
234
224
  options.headers['X-Zimbra-Csrf-Token'] = requestOptions.csrfToken;
235
-
236
- header.context.csrfToken = requestOptions.csrfToken;
237
225
  }
238
226
 
239
227
  // Allow to set Auth Token in Cookie in case `ZimbraBatchClient` is used on non-web platforms, like nodejs
@@ -267,7 +255,7 @@ export function jsonRequest(requestOptions: JsonRequestOptions): Promise<Request
267
255
  })
268
256
  .then(parseJSON)
269
257
  .then((response: any) => {
270
- const globalFault = get(response.parsed, 'Body.Fault');
258
+ const globalFault = response?.parsed?.Body?.Fault;
271
259
 
272
260
  if (globalFault) {
273
261
  throw faultError(response, globalFault);