@muyichengshayu/promptx 0.2.2 → 0.2.3

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.
@@ -3,17 +3,19 @@ import process from 'node:process'
3
3
  import { spawn } from 'node:child_process'
4
4
  import { fileURLToPath } from 'node:url'
5
5
 
6
- const DEFAULT_TIMEOUT_MS = 20_000
6
+ const DEFAULT_TIMEOUT_MS = Math.max(1_000, Number(process.env.PROMPTX_GIT_DIFF_TIMEOUT_MS) || 60_000)
7
+ const DEFAULT_MAX_WORKERS = Math.max(1, Number(process.env.PROMPTX_GIT_DIFF_WORKER_POOL_SIZE) || 2)
7
8
  const MAX_STDERR_LENGTH = 4000
8
9
 
9
10
  const currentDir = path.dirname(fileURLToPath(import.meta.url))
10
11
  const workerEntryPath = path.join(currentDir, 'gitDiffWorker.js')
11
12
 
12
- let workerProcess = null
13
- let workerStdoutBuffer = ''
14
- let workerStderrBuffer = ''
15
13
  let nextRequestId = 1
16
- const pendingRequests = new Map()
14
+ let nextWorkerId = 1
15
+ const workerPool = []
16
+ const requestQueue = []
17
+ const requestMap = new Map()
18
+ const activeRequests = new Map()
17
19
  const workerMetrics = {
18
20
  startedAt: new Date().toISOString(),
19
21
  spawnCount: 0,
@@ -44,11 +46,6 @@ function createWorkerError(message = '') {
44
46
  return error
45
47
  }
46
48
 
47
- function resetWorkerBuffers() {
48
- workerStdoutBuffer = ''
49
- workerStderrBuffer = ''
50
- }
51
-
52
49
  function createLastRequestSnapshot(request = {}, patch = {}) {
53
50
  return {
54
51
  requestId: String(request.requestId || patch.requestId || '').trim(),
@@ -68,91 +65,266 @@ function markLastRequest(request = {}, patch = {}) {
68
65
  workerMetrics.lastRequest = createLastRequestSnapshot(request, patch)
69
66
  }
70
67
 
71
- function appendWorkerStderr(chunk) {
72
- workerStderrBuffer = `${workerStderrBuffer}${Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk || '')}`
73
- if (workerStderrBuffer.length > MAX_STDERR_LENGTH) {
74
- workerStderrBuffer = workerStderrBuffer.slice(-MAX_STDERR_LENGTH)
68
+ function getNowIso() {
69
+ return new Date().toISOString()
70
+ }
71
+
72
+ function getRequestDurationMs(request = {}) {
73
+ const startedAt = Date.parse(String(request.requestMeta?.startedAt || ''))
74
+ return Number.isFinite(startedAt) ? Math.max(0, Date.now() - startedAt) : 0
75
+ }
76
+
77
+ function getWorkerIndex(workerId = '') {
78
+ return workerPool.findIndex((worker) => worker.id === workerId)
79
+ }
80
+
81
+ function getWorkerById(workerId = '') {
82
+ const index = getWorkerIndex(workerId)
83
+ return index >= 0 ? workerPool[index] : null
84
+ }
85
+
86
+ function removeWorker(worker) {
87
+ const index = getWorkerIndex(worker?.id)
88
+ if (index >= 0) {
89
+ workerPool.splice(index, 1)
90
+ }
91
+ }
92
+
93
+ function clearRequestTimer(request) {
94
+ if (request?.timer) {
95
+ clearTimeout(request.timer)
96
+ request.timer = null
75
97
  }
76
98
  }
77
99
 
78
- function settlePendingRequest(requestId, handler) {
79
- const pending = pendingRequests.get(requestId)
80
- if (!pending) {
100
+ function removeQueuedRequest(requestId = '') {
101
+ const index = requestQueue.findIndex((request) => request.requestId === requestId)
102
+ if (index >= 0) {
103
+ requestQueue.splice(index, 1)
104
+ }
105
+ }
106
+
107
+ function updateWorkerExitMetrics({ code = null, signal = '', reason = '' } = {}) {
108
+ workerMetrics.lastWorkerExitAt = getNowIso()
109
+ workerMetrics.lastWorkerExitCode = typeof code === 'number' ? code : null
110
+ workerMetrics.lastWorkerExitSignal = String(signal || '').trim()
111
+ workerMetrics.lastWorkerExitReason = String(reason || '').trim()
112
+ }
113
+
114
+ function finalizeRequest(request, handler) {
115
+ if (!request || request.settled) {
81
116
  return
82
117
  }
83
118
 
84
- pendingRequests.delete(requestId)
85
- clearTimeout(pending.timer)
86
- handler(pending)
119
+ request.settled = true
120
+ clearRequestTimer(request)
121
+ removeQueuedRequest(request.requestId)
122
+ requestMap.delete(request.requestId)
123
+ activeRequests.delete(request.requestId)
124
+ handler(request)
87
125
  }
88
126
 
89
- function rejectAllPendingRequests(error) {
90
- for (const [requestId, pending] of pendingRequests.entries()) {
91
- pendingRequests.delete(requestId)
92
- clearTimeout(pending.timer)
127
+ function rejectRequestWithError(request, error) {
128
+ finalizeRequest(request, (pending) => {
129
+ workerMetrics.failedRequests += 1
130
+ markLastRequest(pending.requestMeta, {
131
+ finishedAt: getNowIso(),
132
+ durationMs: getRequestDurationMs(pending),
133
+ status: error?.code === 'GIT_DIFF_TIMEOUT' ? 'timeout' : 'failed',
134
+ timeout: error?.code === 'GIT_DIFF_TIMEOUT',
135
+ errorMessage: String(error?.message || error || 'git diff request failed'),
136
+ })
93
137
  pending.reject(error)
138
+ })
139
+ }
140
+
141
+ function resolveRequest(request, value) {
142
+ finalizeRequest(request, (pending) => {
143
+ workerMetrics.completedRequests += 1
144
+ markLastRequest(pending.requestMeta, {
145
+ finishedAt: getNowIso(),
146
+ durationMs: getRequestDurationMs(pending),
147
+ status: 'completed',
148
+ })
149
+ pending.resolve(value)
150
+ })
151
+ }
152
+
153
+ function createWorkerState(child) {
154
+ return {
155
+ id: `git-diff-worker-${nextWorkerId++}`,
156
+ child,
157
+ stdoutBuffer: '',
158
+ stderrBuffer: '',
159
+ activeRequestId: '',
160
+ startedAt: getNowIso(),
161
+ stopping: false,
162
+ }
163
+ }
164
+
165
+ function appendWorkerStderr(worker, chunk) {
166
+ worker.stderrBuffer = `${worker.stderrBuffer}${Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk || '')}`
167
+ if (worker.stderrBuffer.length > MAX_STDERR_LENGTH) {
168
+ worker.stderrBuffer = worker.stderrBuffer.slice(-MAX_STDERR_LENGTH)
169
+ }
170
+ }
171
+
172
+ function stopWorker(worker, reason = '') {
173
+ if (!worker || worker.stopping) {
174
+ return
175
+ }
176
+
177
+ worker.stopping = true
178
+ removeWorker(worker)
179
+ updateWorkerExitMetrics({
180
+ signal: 'manual_stop',
181
+ reason,
182
+ })
183
+
184
+ if (worker.child?.exitCode === null && !worker.child?.killed) {
185
+ worker.child.kill()
186
+ }
187
+ }
188
+
189
+ function dispatchQueuedRequests() {
190
+ while (requestQueue.length) {
191
+ let worker = workerPool.find((item) => !item.activeRequestId && !item.stopping) || null
192
+ if (!worker && workerPool.length < DEFAULT_MAX_WORKERS) {
193
+ worker = ensureGitDiffWorker()
194
+ }
195
+ if (!worker) {
196
+ return
197
+ }
198
+
199
+ const request = requestQueue.shift()
200
+ if (!request || request.settled) {
201
+ continue
202
+ }
203
+
204
+ request.workerId = worker.id
205
+ worker.activeRequestId = request.requestId
206
+ activeRequests.set(request.requestId, request)
207
+
208
+ try {
209
+ worker.child.stdin?.write(`${JSON.stringify({
210
+ requestId: request.requestId,
211
+ action: 'getTaskGitDiffReview',
212
+ taskSlug: request.taskSlug,
213
+ options: request.options,
214
+ })}\n`)
215
+ } catch (error) {
216
+ worker.activeRequestId = ''
217
+ activeRequests.delete(request.requestId)
218
+ request.workerId = ''
219
+ rejectRequestWithError(request, createWorkerError(String(error?.message || error)))
220
+ stopWorker(worker, String(error?.message || error || 'worker write failed'))
221
+ }
94
222
  }
95
223
  }
96
224
 
97
- function detachWorkerListeners(child) {
98
- child.stdout?.removeAllListeners()
99
- child.stderr?.removeAllListeners()
100
- child.removeAllListeners()
225
+ function settleWorkerRequest(worker, requestId, handler) {
226
+ const request = activeRequests.get(requestId)
227
+ if (!request) {
228
+ return
229
+ }
230
+
231
+ if (worker.activeRequestId === requestId) {
232
+ worker.activeRequestId = ''
233
+ }
234
+ request.workerId = ''
235
+ handler(request)
236
+ dispatchQueuedRequests()
101
237
  }
102
238
 
103
- function handleWorkerLine(line) {
239
+ function handleWorkerLine(worker, line) {
104
240
  let payload
105
241
  try {
106
242
  payload = JSON.parse(line)
107
243
  } catch {
108
- rejectAllPendingRequests(
109
- createWorkerError(`git diff worker returned invalid JSON: ${line.slice(0, 200)}`)
110
- )
111
- stopGitDiffWorker()
244
+ const error = createWorkerError(`git diff worker returned invalid JSON: ${line.slice(0, 200)}`)
245
+ if (worker.activeRequestId) {
246
+ settleWorkerRequest(worker, worker.activeRequestId, (request) => {
247
+ rejectRequestWithError(request, error)
248
+ })
249
+ }
250
+ stopWorker(worker, error.message)
112
251
  return
113
252
  }
114
253
 
115
254
  const requestId = String(payload?.requestId || '').trim()
116
255
  if (!requestId) {
117
- rejectAllPendingRequests(
118
- createWorkerError(String(payload?.error?.message || '').trim() || 'git diff worker returned a response without requestId.')
256
+ const error = createWorkerError(
257
+ String(payload?.error?.message || '').trim() || 'git diff worker returned a response without requestId.'
119
258
  )
120
- stopGitDiffWorker()
259
+ if (worker.activeRequestId) {
260
+ settleWorkerRequest(worker, worker.activeRequestId, (request) => {
261
+ rejectRequestWithError(request, error)
262
+ })
263
+ }
264
+ stopWorker(worker, error.message)
121
265
  return
122
266
  }
123
267
 
124
- settlePendingRequest(requestId, ({ resolve, reject }) => {
268
+ settleWorkerRequest(worker, requestId, (request) => {
125
269
  if (!payload?.ok) {
126
- reject(createWorkerError(String(payload?.error?.message || '').trim() || workerStderrBuffer.trim()))
270
+ const error = createWorkerError(String(payload?.error?.message || '').trim() || worker.stderrBuffer.trim())
271
+ rejectRequestWithError(request, error)
127
272
  return
128
273
  }
129
- resolve(payload.result)
274
+ resolveRequest(request, payload.result)
130
275
  })
131
276
  }
132
277
 
133
- function handleWorkerStdout(chunk) {
134
- workerStdoutBuffer = `${workerStdoutBuffer}${Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk || '')}`
278
+ function handleWorkerStdout(worker, chunk) {
279
+ worker.stdoutBuffer = `${worker.stdoutBuffer}${Buffer.isBuffer(chunk) ? chunk.toString('utf8') : String(chunk || '')}`
135
280
 
136
- let newlineIndex = workerStdoutBuffer.indexOf('\n')
281
+ let newlineIndex = worker.stdoutBuffer.indexOf('\n')
137
282
  while (newlineIndex !== -1) {
138
- const line = workerStdoutBuffer.slice(0, newlineIndex).trim()
139
- workerStdoutBuffer = workerStdoutBuffer.slice(newlineIndex + 1)
283
+ const line = worker.stdoutBuffer.slice(0, newlineIndex).trim()
284
+ worker.stdoutBuffer = worker.stdoutBuffer.slice(newlineIndex + 1)
140
285
  if (line) {
141
- handleWorkerLine(line)
286
+ handleWorkerLine(worker, line)
142
287
  }
143
- newlineIndex = workerStdoutBuffer.indexOf('\n')
288
+ newlineIndex = worker.stdoutBuffer.indexOf('\n')
144
289
  }
145
290
  }
146
291
 
147
- function ensureGitDiffWorker() {
148
- if (workerProcess && !workerProcess.killed && workerProcess.exitCode === null) {
149
- return workerProcess
292
+ function handleWorkerFailure(worker, error) {
293
+ removeWorker(worker)
294
+ updateWorkerExitMetrics({
295
+ reason: String(error?.message || error || 'worker error'),
296
+ })
297
+
298
+ if (worker.activeRequestId) {
299
+ settleWorkerRequest(worker, worker.activeRequestId, (request) => {
300
+ rejectRequestWithError(request, createWorkerError(String(error?.message || error)))
301
+ })
150
302
  }
151
303
 
152
- resetWorkerBuffers()
153
- if (workerMetrics.spawnCount > 0) {
154
- workerMetrics.restartCount += 1
304
+ dispatchQueuedRequests()
305
+ }
306
+
307
+ function handleWorkerClose(worker, code, signal) {
308
+ removeWorker(worker)
309
+ updateWorkerExitMetrics({
310
+ code,
311
+ signal,
312
+ reason: worker.stderrBuffer.trim() || (signal ? `signal:${signal}` : `code:${code}`),
313
+ })
314
+
315
+ if (worker.activeRequestId) {
316
+ const error = worker.stderrBuffer.trim()
317
+ ? createWorkerError(`git diff worker exited unexpectedly: ${worker.stderrBuffer.trim()}`)
318
+ : createWorkerError('git diff worker exited unexpectedly.')
319
+ settleWorkerRequest(worker, worker.activeRequestId, (request) => {
320
+ rejectRequestWithError(request, error)
321
+ })
155
322
  }
323
+
324
+ dispatchQueuedRequests()
325
+ }
326
+
327
+ function ensureGitDiffWorker() {
156
328
  const child = spawn(process.execPath, [workerEntryPath], {
157
329
  cwd: currentDir,
158
330
  env: {
@@ -161,58 +333,46 @@ function ensureGitDiffWorker() {
161
333
  stdio: ['pipe', 'pipe', 'pipe'],
162
334
  windowsHide: true,
163
335
  })
336
+
337
+ if (workerMetrics.spawnCount > 0) {
338
+ workerMetrics.restartCount += 1
339
+ }
340
+
341
+ const worker = createWorkerState(child)
342
+ workerPool.push(worker)
164
343
  workerMetrics.spawnCount += 1
165
- workerMetrics.lastWorkerSpawnedAt = new Date().toISOString()
344
+ workerMetrics.lastWorkerSpawnedAt = worker.startedAt
166
345
 
167
- child.stdout?.on('data', handleWorkerStdout)
168
- child.stderr?.on('data', appendWorkerStderr)
346
+ child.stdout?.on('data', (chunk) => {
347
+ handleWorkerStdout(worker, chunk)
348
+ })
349
+ child.stderr?.on('data', (chunk) => {
350
+ appendWorkerStderr(worker, chunk)
351
+ })
169
352
  child.on('error', (error) => {
170
- workerMetrics.lastWorkerExitAt = new Date().toISOString()
171
- workerMetrics.lastWorkerExitCode = null
172
- workerMetrics.lastWorkerExitSignal = ''
173
- workerMetrics.lastWorkerExitReason = String(error?.message || error || 'worker error')
174
- rejectAllPendingRequests(createWorkerError(String(error?.message || error)))
175
- if (workerProcess === child) {
176
- workerProcess = null
177
- }
178
- detachWorkerListeners(child)
353
+ handleWorkerFailure(worker, error)
179
354
  })
180
355
  child.on('close', (code, signal) => {
181
- const tail = workerStderrBuffer.trim()
182
- workerMetrics.lastWorkerExitAt = new Date().toISOString()
183
- workerMetrics.lastWorkerExitCode = typeof code === 'number' ? code : null
184
- workerMetrics.lastWorkerExitSignal = String(signal || '').trim()
185
- workerMetrics.lastWorkerExitReason = tail || (signal ? `signal:${signal}` : `code:${code}`)
186
- rejectAllPendingRequests(
187
- tail
188
- ? createWorkerError(`git diff worker exited unexpectedly: ${tail}`)
189
- : createWorkerError('git diff worker exited unexpectedly.')
190
- )
191
- if (workerProcess === child) {
192
- workerProcess = null
193
- }
194
- detachWorkerListeners(child)
195
- resetWorkerBuffers()
356
+ handleWorkerClose(worker, code, signal)
196
357
  })
197
358
 
198
- workerProcess = child
199
- return child
359
+ return worker
200
360
  }
201
361
 
202
362
  export function stopGitDiffWorker() {
203
- if (!workerProcess) {
204
- return
205
- }
363
+ const stopError = createWorkerError('git diff worker stopped.')
206
364
 
207
- const child = workerProcess
208
- workerProcess = null
209
- rejectAllPendingRequests(createWorkerError('git diff worker stopped.'))
210
- detachWorkerListeners(child)
211
- resetWorkerBuffers()
365
+ requestQueue.splice(0, requestQueue.length).forEach((request) => {
366
+ rejectRequestWithError(request, stopError)
367
+ })
212
368
 
213
- if (child.exitCode === null && !child.killed) {
214
- child.kill()
369
+ for (const request of [...activeRequests.values()]) {
370
+ rejectRequestWithError(request, stopError)
215
371
  }
372
+
373
+ ;[...workerPool].forEach((worker) => {
374
+ stopWorker(worker, 'stopped')
375
+ })
216
376
  }
217
377
 
218
378
  export function getTaskGitDiffReviewInSubprocess(taskSlug = '', options = {}) {
@@ -223,81 +383,83 @@ export function getTaskGitDiffReviewInSubprocess(taskSlug = '', options = {}) {
223
383
  taskSlug: String(taskSlug || '').trim(),
224
384
  scope: String(options.scope || '').trim(),
225
385
  filePath: String(options.filePath || '').trim(),
226
- startedAt: new Date().toISOString(),
386
+ startedAt: getNowIso(),
227
387
  }
228
- const child = ensureGitDiffWorker()
388
+
229
389
  workerMetrics.totalRequests += 1
230
390
 
231
391
  return new Promise((resolve, reject) => {
232
- const timer = setTimeout(() => {
233
- pendingRequests.delete(requestId)
234
- workerMetrics.timeoutRequests += 1
235
- workerMetrics.failedRequests += 1
236
- markLastRequest(requestMeta, {
237
- finishedAt: new Date().toISOString(),
238
- durationMs: Date.now() - Date.parse(requestMeta.startedAt),
239
- status: 'timeout',
240
- timeout: true,
241
- errorMessage: `git diff request timed out after ${timeoutMs}ms`,
242
- })
243
- stopGitDiffWorker()
244
- reject(createTimeoutError(timeoutMs))
245
- }, timeoutMs)
246
-
247
- pendingRequests.set(requestId, {
248
- resolve: (value) => {
249
- workerMetrics.completedRequests += 1
250
- markLastRequest(requestMeta, {
251
- finishedAt: new Date().toISOString(),
252
- durationMs: Date.now() - Date.parse(requestMeta.startedAt),
253
- status: 'completed',
254
- })
255
- resolve(value)
256
- },
257
- reject: (error) => {
258
- workerMetrics.failedRequests += 1
259
- markLastRequest(requestMeta, {
260
- finishedAt: new Date().toISOString(),
261
- durationMs: Date.now() - Date.parse(requestMeta.startedAt),
262
- status: error?.code === 'GIT_DIFF_TIMEOUT' ? 'timeout' : 'failed',
263
- timeout: error?.code === 'GIT_DIFF_TIMEOUT',
264
- errorMessage: String(error?.message || error || 'git diff request failed'),
265
- })
266
- reject(error)
267
- },
268
- timer,
269
- })
270
-
271
- try {
272
- child.stdin?.write(`${JSON.stringify({
273
- requestId,
274
- action: 'getTaskGitDiffReview',
275
- taskSlug: String(taskSlug || '').trim(),
276
- options,
277
- })}\n`)
278
- } catch (error) {
279
- settlePendingRequest(requestId, ({ reject: rejectPending }) => {
280
- rejectPending(createWorkerError(String(error?.message || error)))
281
- })
282
- stopGitDiffWorker()
392
+ const request = {
393
+ requestId,
394
+ taskSlug: String(taskSlug || '').trim(),
395
+ options,
396
+ resolve,
397
+ reject,
398
+ requestMeta,
399
+ settled: false,
400
+ workerId: '',
401
+ timer: setTimeout(() => {
402
+ const currentRequest = requestMap.get(requestId)
403
+ if (!currentRequest || currentRequest.settled) {
404
+ return
405
+ }
406
+
407
+ workerMetrics.timeoutRequests += 1
408
+ const timeoutError = createTimeoutError(timeoutMs)
409
+ if (currentRequest.workerId) {
410
+ const worker = getWorkerById(currentRequest.workerId)
411
+ if (worker && worker.activeRequestId === requestId) {
412
+ worker.activeRequestId = ''
413
+ }
414
+ rejectRequestWithError(currentRequest, timeoutError)
415
+ if (worker) {
416
+ stopWorker(worker, `request_timeout:${requestId}`)
417
+ }
418
+ dispatchQueuedRequests()
419
+ return
420
+ }
421
+
422
+ rejectRequestWithError(currentRequest, timeoutError)
423
+ }, timeoutMs),
283
424
  }
425
+
426
+ request.timer.unref?.()
427
+ requestMap.set(requestId, request)
428
+ requestQueue.push(request)
429
+ dispatchQueuedRequests()
284
430
  })
285
431
  }
286
432
 
287
433
  export function __getGitDiffWorkerPidForTest() {
288
- return Number(workerProcess?.pid || 0)
434
+ return Number(workerPool[0]?.child?.pid || 0)
435
+ }
436
+
437
+ export function __getGitDiffWorkerPidsForTest() {
438
+ return workerPool.map((worker) => Number(worker.child?.pid || 0)).filter((pid) => pid > 0)
289
439
  }
290
440
 
291
441
  export function getGitDiffWorkerDiagnostics() {
292
442
  return {
293
443
  worker: {
294
- pid: Number(workerProcess?.pid || 0),
295
- running: Boolean(workerProcess && !workerProcess.killed && workerProcess.exitCode === null),
296
- pendingRequests: pendingRequests.size,
297
- stderrTail: workerStderrBuffer.trim(),
444
+ pid: Number(workerPool[0]?.child?.pid || 0),
445
+ running: workerPool.some((worker) => !worker.stopping && worker.child?.exitCode === null && !worker.child?.killed),
446
+ pendingRequests: requestQueue.length + activeRequests.size,
447
+ stderrTail: String(workerPool[0]?.stderrBuffer || '').trim(),
298
448
  },
449
+ workers: workerPool.map((worker) => ({
450
+ id: worker.id,
451
+ pid: Number(worker.child?.pid || 0),
452
+ running: !worker.stopping && worker.child?.exitCode === null && !worker.child?.killed,
453
+ activeRequestId: String(worker.activeRequestId || '').trim(),
454
+ stderrTail: String(worker.stderrBuffer || '').trim(),
455
+ startedAt: worker.startedAt,
456
+ })),
299
457
  metrics: {
300
458
  ...workerMetrics,
459
+ maxWorkers: DEFAULT_MAX_WORKERS,
460
+ queueDepth: requestQueue.length,
461
+ activeRequestCount: activeRequests.size,
462
+ workerCount: workerPool.length,
301
463
  lastWorkerExitSignal: String(workerMetrics.lastWorkerExitSignal || ''),
302
464
  lastWorkerExitReason: String(workerMetrics.lastWorkerExitReason || ''),
303
465
  lastRequest: workerMetrics.lastRequest ? { ...workerMetrics.lastRequest } : null,
@@ -413,6 +413,7 @@ function registerTaskRoutes(app, options = {}) {
413
413
  filePath: request.query?.filePath,
414
414
  includeFiles: String(request.query?.includeFiles || '').trim() !== 'false',
415
415
  includeStats: String(request.query?.includeStats || '').trim() !== 'false',
416
+ timeoutMs: request.query?.timeoutMs,
416
417
  })
417
418
  } catch (error) {
418
419
  if (error?.statusCode) {