@open-xchange/soap-client 0.0.7 → 0.0.8

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": "@open-xchange/soap-client",
3
- "version": "0.0.7",
3
+ "version": "0.0.8",
4
4
  "description": "SOAP client for OX App Suite",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -20,23 +20,23 @@
20
20
 
21
21
  import { createClientAsync, logSoapError } from '../../soap.js'
22
22
 
23
- const OXContextService = createClientAsync('OXContextService').then(client => client)
23
+ const OXContextService = createClientAsync('OXContextService')
24
24
 
25
25
  /**
26
26
  * This function retrieves the default context from the OXContextService.
27
27
  * @returns {Promise<Object>} The first result from the listAsync method call.
28
28
  */
29
29
  export async function getDefault () {
30
- return (await (await OXContextService).listAsync({ search_pattern: 'defaultcontext' }))[0]
30
+ return (await OXContextService).listAsync({ search_pattern: 'defaultcontext' })[0]
31
31
  }
32
32
 
33
33
  /**
34
34
  * This function removes the context with the specified ID.
35
+ * Fire-and-forget operation - spawns a separate process to avoid blocking.
35
36
  * @param {number} id The ID of the context to remove.
36
- * @returns {Promise<Boolean>} Returns true if it could remove the context and false if it could not
37
37
  */
38
38
  export async function remove (id) {
39
- return !!await (await OXContextService).deleteAsync({ ctx: { id } }).then(() => true).catch(logSoapError)
39
+ return (await OXContextService).deleteAsync({ ctx: { id } })
40
40
  }
41
41
 
42
42
  /**
@@ -59,7 +59,7 @@ export async function remove (id) {
59
59
  * @returns {Promise<Object>} The created context.
60
60
  */
61
61
  export async function create (ctx = {}, adminUser = {}, accessCombinationName = 'all') {
62
- return await (await OXContextService)
62
+ return (await OXContextService)
63
63
  .createAsync({
64
64
  ctx,
65
65
  admin_user: Object.assign({
@@ -91,7 +91,7 @@ export async function create (ctx = {}, adminUser = {}, accessCombinationName =
91
91
  // eslint-disable-next-line camelcase
92
92
  export async function changeModuleAccessByName (id, access_combination_name) {
93
93
  // eslint-disable-next-line camelcase
94
- return await (await OXContextService).changeModuleAccessByNameAsync({ ctx: { id }, access_combination_name })
94
+ return (await OXContextService).changeModuleAccessByNameAsync({ ctx: { id }, access_combination_name })
95
95
  }
96
96
 
97
97
  /**
@@ -105,7 +105,7 @@ export async function changeCapabilities (id, capsToAdd, capsToRemove) {
105
105
  const data = {}
106
106
  if (capsToAdd) data.capsToAdd = capsToAdd
107
107
  if (capsToRemove) data.capsToRemove = capsToRemove
108
- return await (await OXContextService).changeCapabilitiesAsync({ ctx: { id }, ...data })
108
+ return (await OXContextService).changeCapabilitiesAsync({ ctx: { id }, ...data })
109
109
  }
110
110
 
111
111
  /**
@@ -114,7 +114,7 @@ export async function changeCapabilities (id, capsToAdd, capsToRemove) {
114
114
  * @returns {Promise<Object>} The module access of the specified context.
115
115
  */
116
116
  export async function getModuleAccess (id) {
117
- return await (await OXContextService).getModuleAccessAsync({ ctx: { id } })
117
+ return (await OXContextService).getModuleAccessAsync({ ctx: { id } })
118
118
  }
119
119
  /**
120
120
  * This function changes the module access of the specified context.
@@ -124,7 +124,7 @@ export async function getModuleAccess (id) {
124
124
  */
125
125
  export async function changeModuleAccess (id, moduleAccess) {
126
126
  const currentAccess = await getModuleAccess(id)
127
- return await (await OXContextService).changeModuleAccessAsync({ ctx: { id }, access: { ...currentAccess, ...moduleAccess } })
127
+ return (await OXContextService).changeModuleAccessAsync({ ctx: { id }, access: { ...currentAccess, ...moduleAccess } })
128
128
  }
129
129
 
130
130
  /**
@@ -135,7 +135,10 @@ export async function changeModuleAccess (id, moduleAccess) {
135
135
  * @returns {Promise<Array<Object>>} The list of contexts that match the search pattern.
136
136
  */
137
137
  export async function list (searchPattern, { excludeDisabled } = { excludeDisabled: true }) {
138
- return await (await OXContextService).listAsync({ search_pattern: searchPattern, exclude_disabled: excludeDisabled })
138
+ return (await OXContextService).listAsync({ search_pattern: searchPattern, exclude_disabled: excludeDisabled }).catch(e => {
139
+ logSoapError(e)
140
+ return []
141
+ })
139
142
  }
140
143
 
141
144
  /**
@@ -144,7 +147,7 @@ export async function list (searchPattern, { excludeDisabled } = { excludeDisabl
144
147
  * @returns {Promise<Object>} The context with the specified ID.
145
148
  */
146
149
  export async function get (id) {
147
- return await (await OXContextService).getDataAsync({ ctx: { id } })
150
+ return (await OXContextService).getDataAsync({ ctx: { id } })
148
151
  }
149
152
 
150
153
  /**
@@ -153,5 +156,5 @@ export async function get (id) {
153
156
  * @returns {Promise<void>}
154
157
  */
155
158
  export async function change (ctx) {
156
- return await (await OXContextService).changeAsync({ ctx })
159
+ return (await OXContextService).changeAsync({ ctx })
157
160
  }
@@ -20,7 +20,7 @@
20
20
 
21
21
  import { createClientAsync, logSoapError } from '../../soap.js'
22
22
 
23
- const OXUserService = createClientAsync('OXUserService').then(client => client)
23
+ const OXUserService = createClientAsync('OXUserService')
24
24
 
25
25
  /**
26
26
  * This function removes the user with the specified context and user ID.
@@ -29,11 +29,11 @@ const OXUserService = createClientAsync('OXUserService').then(client => client)
29
29
  * @returns {Promise<Boolean>} Returns true if it could remove the user and false if it could not
30
30
  */
31
31
  export async function remove (context, userId) {
32
- return !!await (await OXUserService).deleteAsync({
32
+ return (await OXUserService).deleteAsync({
33
33
  ctx: { id: context.id },
34
34
  user: { id: userId },
35
35
  auth: context.admin
36
- }).then(() => true).catch(logSoapError)
36
+ }).catch(logSoapError)
37
37
  }
38
38
 
39
39
  /**
@@ -43,7 +43,7 @@ export async function remove (context, userId) {
43
43
  * @returns {Promise<Object>} The created user.
44
44
  */
45
45
  export async function create (context, usrdata) {
46
- return await (await OXUserService).createAsync({
46
+ return (await OXUserService).createAsync({
47
47
  ctx: { id: context.id },
48
48
  usrdata,
49
49
  auth: context.admin
@@ -57,7 +57,7 @@ export async function create (context, usrdata) {
57
57
  * @returns {Promise<void>}
58
58
  */
59
59
  export async function change (context, usrdata) {
60
- return await (await OXUserService).changeAsync({
60
+ return (await OXUserService).changeAsync({
61
61
  ctx: { id: context.id },
62
62
  usrdata,
63
63
  auth: context.admin
@@ -65,7 +65,7 @@ export async function change (context, usrdata) {
65
65
  }
66
66
 
67
67
  export async function changeByModuleAccess (context, userId, currentAccess, moduleAccess) {
68
- return await (await OXUserService).changeByModuleAccessAsync({
68
+ return (await OXUserService).changeByModuleAccessAsync({
69
69
  ctx: { id: context.id },
70
70
  moduleAccess: Object.assign({}, currentAccess, moduleAccess),
71
71
  user: { id: userId },
@@ -74,7 +74,7 @@ export async function changeByModuleAccess (context, userId, currentAccess, modu
74
74
  }
75
75
 
76
76
  export async function changeByModuleAccessName (context, userId, accessCombinationName) {
77
- return await (await OXUserService).changeByModuleAccessNameAsync({
77
+ return (await OXUserService).changeByModuleAccessNameAsync({
78
78
  ctx: { id: context.id },
79
79
  access_combination_name: accessCombinationName,
80
80
  user: { id: userId },
@@ -83,7 +83,7 @@ export async function changeByModuleAccessName (context, userId, accessCombinati
83
83
  }
84
84
 
85
85
  export async function getModuleAccess (context, userId) {
86
- return await (await OXUserService).getModuleAccessAsync({
86
+ return (await OXUserService).getModuleAccessAsync({
87
87
  ctx: { id: context.id },
88
88
  user: { id: userId },
89
89
  auth: context.admin
@@ -100,11 +100,11 @@ export async function changeCapabilities (context, userId, capsToAdd, capsToRemo
100
100
  }
101
101
  if (capsToAdd) data.capsToAdd = capsToAdd
102
102
  if (capsToRemove) data.capsToRemove = capsToRemove
103
- return await (await OXUserService).changeCapabilitiesAsync(data)
103
+ return (await OXUserService).changeCapabilitiesAsync(data)
104
104
  }
105
105
 
106
106
  export async function exists (context, userId) {
107
- return await (await OXUserService).existsAsync({
107
+ return (await OXUserService).existsAsync({
108
108
  ctx: { id: context.id },
109
109
  user: { id: userId },
110
110
  auth: context.admin
@@ -112,7 +112,7 @@ export async function exists (context, userId) {
112
112
  }
113
113
 
114
114
  export async function list (context, searchPattern, includeGuests = false) {
115
- return await (await OXUserService).listAsync({
115
+ return (await OXUserService).listAsync({
116
116
  ctx: { id: context.id },
117
117
  search_pattern: searchPattern,
118
118
  include_guests: includeGuests,
@@ -121,7 +121,7 @@ export async function list (context, searchPattern, includeGuests = false) {
121
121
  }
122
122
 
123
123
  export async function listAll (context, includeGuests = false, excludeUsers = []) {
124
- return await (await OXUserService).listAsync({
124
+ return (await OXUserService).listAsync({
125
125
  ctx: { id: context.id },
126
126
  include_guests: includeGuests,
127
127
  exclude_users: excludeUsers,
@@ -27,7 +27,7 @@ import { createClientAsync } from '../../soap.js'
27
27
  let fileStoreId
28
28
 
29
29
  export async function getFilestorageId () {
30
- const OXUtilService = createClientAsync('OXUtilService').then(client => client)
30
+ const OXUtilService = createClientAsync('OXUtilService')
31
31
 
32
32
  if (fileStoreId) return fileStoreId
33
33
  fileStoreId = (await (await OXUtilService).listFilestoreAsync())[0]?.id
@@ -23,9 +23,9 @@ import { createClientAsync } from '../../soap.js'
23
23
  const OXaaSService = createClientAsync('OXaaSService').then(client => client)
24
24
 
25
25
  export async function setMailQuota (data) {
26
- return await (await OXaaSService).setMailQuotaAsync(data)
26
+ return (await OXaaSService).setMailQuotaAsync(data)
27
27
  }
28
28
 
29
29
  export async function createSharedDomain (data) {
30
- return await (await OXaaSService).createSharedDomain(data)
30
+ return (await OXaaSService).createSharedDomain(data)
31
31
  }
@@ -20,36 +20,36 @@
20
20
 
21
21
  import { createClientAsync, logSoapError } from '../../soap.js'
22
22
 
23
- const OXResellerContextService = createClientAsync('OXResellerContextService').then(client => client)
23
+ const OXResellerContextService = createClientAsync('OXResellerContextService')
24
24
 
25
25
  export async function create (data) {
26
- return await (await OXResellerContextService).createAsync(data)
26
+ return (await OXResellerContextService).createAsync(data)
27
27
  }
28
28
 
29
29
  export async function remove (contextId) {
30
- return !!await (await OXResellerContextService).deleteAsync({
30
+ return (await OXResellerContextService).deleteAsync({
31
31
  ctx: { id: contextId }
32
- }).then(() => true).catch(logSoapError)
32
+ }).catch(logSoapError)
33
33
  }
34
34
 
35
35
  export async function change (ctx) {
36
- return await (await OXResellerContextService).changeAsync({ ctx })
36
+ return (await OXResellerContextService).changeAsync({ ctx })
37
37
  }
38
38
 
39
39
  export async function get (id) {
40
- return await (await OXResellerContextService).getDataAsync({ ctx: { id } })
40
+ return (await OXResellerContextService).getDataAsync({ ctx: { id } })
41
41
  }
42
42
 
43
43
  export async function getModuleAccess (id) {
44
- return await (await OXResellerContextService).getModuleAccessAsync({ ctx: id })
44
+ return (await OXResellerContextService).getModuleAccessAsync({ ctx: id })
45
45
  }
46
46
 
47
47
  export async function changeModuleAccess (id, access) {
48
48
  const currentAccess = await getModuleAccess(id)
49
49
 
50
- return await (await OXResellerContextService).changeModuleAccessAsync({ ctx: { id }, access: { ...currentAccess, ...access } })
50
+ return (await OXResellerContextService).changeModuleAccessAsync({ ctx: { id }, access: { ...currentAccess, ...access } })
51
51
  }
52
52
 
53
53
  export async function listAll (data) {
54
- return await (await OXResellerContextService).listAllAsync(data)
54
+ return (await OXResellerContextService).listAllAsync(data)
55
55
  }
@@ -23,10 +23,10 @@ import { createClientAsync, logSoapError } from '../../soap.js'
23
23
  const OXResellerUserService = createClientAsync('OXResellerUserService').then(client => client)
24
24
 
25
25
  export async function remove (contextId, userId) {
26
- return !!await (await OXResellerUserService).deleteAsync({
26
+ return (await OXResellerUserService).deleteAsync({
27
27
  ctx: { id: contextId },
28
28
  user: { id: userId }
29
- }).then(() => true).catch(logSoapError)
29
+ }).catch(logSoapError)
30
30
  }
31
31
 
32
32
  /**
@@ -36,7 +36,7 @@ export async function remove (contextId, userId) {
36
36
  * @returns {Promise<void>}
37
37
  */
38
38
  export async function change (context, usrdata) {
39
- return await (await OXResellerUserService).changeAsync({
39
+ return (await OXResellerUserService).changeAsync({
40
40
  ctx: { id: context.id },
41
41
  usrdata,
42
42
  auth: { login: context.admin.name, password: context.admin.password }
@@ -44,11 +44,11 @@ export async function change (context, usrdata) {
44
44
  }
45
45
 
46
46
  export async function get (data) {
47
- return await (await OXResellerUserService).getDataAsync(data)
47
+ return (await OXResellerUserService).getDataAsync(data)
48
48
  }
49
49
 
50
50
  export async function getModuleAccess (context, userId) {
51
- return await (await OXResellerUserService).getModuleAccessAsync({
51
+ return (await OXResellerUserService).getModuleAccessAsync({
52
52
  ctx: { id: context.id },
53
53
  user: { id: userId },
54
54
  auth: { login: context.admin.name, password: context.admin.password }
@@ -58,7 +58,7 @@ export async function getModuleAccess (context, userId) {
58
58
  }
59
59
 
60
60
  export async function changeByModuleAccess (context, userId, currentAccess, moduleAccess) {
61
- return await (await OXResellerUserService).changeByModuleAccessAsync({
61
+ return (await OXResellerUserService).changeByModuleAccessAsync({
62
62
  ctx: { id: context.id },
63
63
  moduleAccess: Object.assign({}, currentAccess, moduleAccess),
64
64
  user: { id: userId },
@@ -67,7 +67,7 @@ export async function changeByModuleAccess (context, userId, currentAccess, modu
67
67
  }
68
68
 
69
69
  export async function changeByModuleAccessName (context, userId, accessCombinationName) {
70
- return await (await OXResellerUserService).changeByModuleAccessNameAsync({
70
+ return (await OXResellerUserService).changeByModuleAccessNameAsync({
71
71
  ctx: { id: context.id },
72
72
  access_combination_name: accessCombinationName,
73
73
  user: { id: userId },
@@ -76,7 +76,7 @@ export async function changeByModuleAccessName (context, userId, accessCombinati
76
76
  }
77
77
 
78
78
  export async function createByModuleAccessName (context, usrdata) {
79
- return await (await OXResellerUserService).createByModuleAccessNameAsync({
79
+ return (await OXResellerUserService).createByModuleAccessNameAsync({
80
80
  ctx: { id: context.id },
81
81
  usrdata,
82
82
  access_combination_name: 'all',
@@ -1,6 +1,6 @@
1
1
  import { createClientAsync } from '../soap.js'
2
2
 
3
- const OXSecondaryAccountService = createClientAsync('OXSecondaryAccountService').then(client => client)
3
+ const OXSecondaryAccountService = createClientAsync('OXSecondaryAccountService')
4
4
 
5
5
  /**
6
6
  * Creates a secondary account using the OX Secondary Account Service
@@ -13,7 +13,7 @@ const OXSecondaryAccountService = createClientAsync('OXSecondaryAccountService')
13
13
  * @throws {Error} If the account creation fails
14
14
  */
15
15
  export async function create (accountData, context, users = [], groups = []) {
16
- return await (await OXSecondaryAccountService).createAsync({
16
+ return (await OXSecondaryAccountService).createAsync({
17
17
  accountDataOnCreate: accountData,
18
18
  context: { id: context.id },
19
19
  users: users || [],
@@ -22,13 +22,13 @@ export async function create (accountData, context, users = [], groups = []) {
22
22
  }
23
23
 
24
24
  export async function list (context) {
25
- return await (await OXSecondaryAccountService).listAsync({
25
+ return (await OXSecondaryAccountService).listAsync({
26
26
  context: { id: context.id },
27
27
  auth: context.admin
28
28
  })
29
29
  }
30
30
  export async function remove (primaryAddress, context, users, groups) {
31
- return await (await OXSecondaryAccountService).deleteAsync({
31
+ return (await OXSecondaryAccountService).deleteAsync({
32
32
  primaryAddress,
33
33
  context: { id: context.id },
34
34
  users,
@@ -37,7 +37,7 @@ export async function remove (primaryAddress, context, users, groups) {
37
37
  }
38
38
 
39
39
  export async function update (primaryAddress, accountData, context, users, groups) {
40
- return await (await OXSecondaryAccountService).updateAsync({
40
+ return (await OXSecondaryAccountService).updateAsync({
41
41
  primaryAddress,
42
42
  accountDataUpdate: accountData,
43
43
  context: { id: context.id },
package/soap.js CHANGED
@@ -31,6 +31,16 @@ dotenv.config({ path: ['.env', '.env.defaults'], quiet: true })
31
31
  // This flag enables debug output including timing information.
32
32
  const debug = process.env.DEBUG_SOAP === 'true'
33
33
 
34
+ // Handle specifically timeout-related unhandled promise rejections as fallback
35
+ process.on('unhandledRejection', (reason, promise) => {
36
+ if (reason?.code === 'ECONNABORTED' && (reason?.message?.includes('timeout') || reason?.message?.includes('exceeded'))) {
37
+ return
38
+ }
39
+
40
+ // Log other unhandled rejections as they indicate real problems
41
+ console.error('Unhandled promise rejection:', reason?.message || reason)
42
+ })
43
+
34
44
  // This URL is used to create the SOAP client.
35
45
  const provisioningUrl = String(process.env.PROVISIONING_URL).replace(/\/$/, '')
36
46
 
@@ -70,6 +80,16 @@ async function logSoapError (e) {
70
80
  **/
71
81
  function shouldAbortRetry (error) {
72
82
  try {
83
+ // Handle timeout errors - these should NOT abort retry, let them retry
84
+ if (error?.code === 'ETIMEDOUT' || error?.code === 'ECONNRESET' || error?.code === 'ECONNABORTED' || error?.message?.includes('timeout')) {
85
+ return false // Allow retry for timeout errors
86
+ }
87
+
88
+ // Handle cases where error doesn't have the expected structure
89
+ if (!error?.root?.Envelope?.Body?.Fault) {
90
+ return false // Let it retry for unexpected error structures
91
+ }
92
+
73
93
  const fault = error.root.Envelope.Body.Fault
74
94
  const details = fault.detail
75
95
  const blockedFaultStrings = [
@@ -144,21 +164,27 @@ async function createClientAsync (type) {
144
164
  soapOptions.auth = { login: soapOptions.auth.login, password: soapOptions.auth.password }
145
165
  }
146
166
 
147
- const result = await pRetry(() => origMethod.apply(this, [soapOptions, { timeout: 30000, ...clientOptions }, ...args]), {
148
- retries: 3,
149
- onFailedAttempt: async error => {
150
- if (shouldAbortRetry(error)) throw new AbortError(error)
151
- console.log(`Attempt ${error.attemptNumber} failed. There are ${error.retriesLeft} retries left.`)
152
- }
153
- }).catch(e => {
167
+ try {
168
+ const result = await pRetry(() => origMethod.apply(this, [soapOptions, { timeout: 30000, ...clientOptions }, ...args]), {
169
+ retries: 3,
170
+ onFailedAttempt: async error => {
171
+ if (shouldAbortRetry(error)) throw new AbortError(error)
172
+ console.log(`Retrying ${String(prop)} in ${error.retriesLeft} attempts (${error.message})`)
173
+ }
174
+ })
175
+
176
+ performance.mark(endMark)
177
+ performance.measure(` ⏱ SOAP: ${type} -> ${String(prop)}`, startMark, endMark)
178
+
179
+ if (!result || !result[0]) return
180
+ return result[0]?.return
181
+ } catch (e) {
154
182
  const soapError = e?.originalError?.root?.Envelope?.Body?.Fault
155
- throw new Error(soapError?.faultstring || e.message)
156
- })
157
- performance.mark(endMark)
158
- performance.measure(` ⏱ SOAP: ${type} -> ${String(prop)}`, startMark, endMark)
159
- // Return only the first result from the SOAP method call, as we don't need the SOAP envelope and other stuff.
160
- if (!result || !result[0]) return
161
- return result[0]?.return
183
+ if (soapError) {
184
+ throw new Error(`SOAP Fault: ${soapError.faultstring}`)
185
+ }
186
+ throw e
187
+ }
162
188
  }
163
189
  } else {
164
190
  return origMethod