@nxtedition/lib 14.2.1 → 15.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/app.js CHANGED
@@ -1,10 +1,11 @@
1
- const { getDockerSecretsSync } = require('./docker-secrets')
2
- const { getGlobalDispatcher } = require('undici')
1
+ const os = require('node:os')
2
+ const net = require('node:net')
3
+ const assert = require('node:assert')
3
4
  const stream = require('node:stream')
4
5
  const { Buffer } = require('node:buffer')
5
- const net = require('net')
6
+ const { getDockerSecretsSync } = require('./docker-secrets')
7
+ const { getGlobalDispatcher } = require('undici')
6
8
  const fp = require('lodash/fp.js')
7
- const assert = require('node:assert')
8
9
 
9
10
  module.exports = function (appConfig, onTerminate) {
10
11
  let ds
@@ -90,14 +91,21 @@ module.exports = function (appConfig, onTerminate) {
90
91
 
91
92
  const destroyers = []
92
93
 
93
- const instanceId = process.env.NODE_APP_INSTANCE || process.env.pm_id || ''
94
-
95
- const serviceName = appConfig.name + (instanceId && instanceId !== '0' ? `-${instanceId}` : '')
94
+ const serviceName = appConfig.name
95
+ const serviceModule = appConfig.module ?? 'main'
96
96
  const serviceVersion = appConfig.version
97
-
98
- const userAgent =
99
- appConfig.userAgent ||
100
- (serviceName ? `${serviceName}/${serviceVersion || '*'} Node/${process.version}` : null)
97
+ const serviceInstanceId =
98
+ // process.env.name is the pm2 name of the process
99
+ appConfig.instanceId ?? appConfig.containerId ?? process.env.name ?? os.hostname()
100
+
101
+ const userAgent = globalThis.userAgent = (
102
+ appConfig.userAgent ??
103
+ (serviceName &&
104
+ `${serviceName}/${
105
+ serviceVersion || '*'
106
+ } (module:${serviceModule}; instance:${serviceInstanceId}) Node/${process.version}`) ??
107
+ null
108
+ )
101
109
 
102
110
  const terminate = async (finalLogger) => {
103
111
  finalLogger ??= logger
@@ -137,9 +145,10 @@ module.exports = function (appConfig, onTerminate) {
137
145
  {
138
146
  ...loggerConfig,
139
147
  name: serviceName,
148
+ module: serviceModule,
140
149
  base: loggerConfig?.base ? { ...loggerConfig.base } : {},
141
150
  },
142
- terminate
151
+ terminate,
143
152
  )
144
153
  }
145
154
 
@@ -166,12 +175,7 @@ module.exports = function (appConfig, onTerminate) {
166
175
  }
167
176
 
168
177
  if (appConfig.perf && process.platform === 'linux') {
169
- const os = require('os')
170
-
171
- const containerId = appConfig.containerId ?? os.hostname()
172
- const hostname = process.env.NODE_ENV === 'production' ? containerId : serviceName
173
-
174
- const perfName = typeof appConfig.perf === 'string' ? appConfig.perf : hostname
178
+ const perfName = typeof appConfig.perf === 'string' ? appConfig.perf : serviceInstanceId
175
179
 
176
180
  try {
177
181
  const linuxPerf = require('linux-perf')
@@ -225,7 +229,7 @@ module.exports = function (appConfig, onTerminate) {
225
229
  } else {
226
230
  return {}
227
231
  }
228
- })
232
+ }),
229
233
  )
230
234
 
231
235
  if (couchConfig.url) {
@@ -253,7 +257,7 @@ module.exports = function (appConfig, onTerminate) {
253
257
  } else {
254
258
  return {}
255
259
  }
256
- })
260
+ }),
257
261
  )
258
262
 
259
263
  if (!dsConfig.credentials || !dsConfig.url) {
@@ -307,7 +311,7 @@ module.exports = function (appConfig, onTerminate) {
307
311
 
308
312
  logger[level](
309
313
  { ds: { connectionState, username: userName, url: dsConfig.url } },
310
- 'Deepstream Connection State Changed.'
314
+ 'Deepstream Connection State Changed.',
311
315
  )
312
316
 
313
317
  prevConnectionState = connectionState
@@ -348,7 +352,7 @@ module.exports = function (appConfig, onTerminate) {
348
352
  rx.exhaustMap(() => {
349
353
  const ret = appConfig.stats({ ds, couch, logger })
350
354
  return ret?.then || ret?.subscribe ? ret : rxjs.of(ret)
351
- })
355
+ }),
352
356
  )
353
357
  } else if (typeof appConfig.stats === 'object') {
354
358
  stats$ = rxjs.timer(0, 10e3).pipe(rx.map(() => appConfig.stats))
@@ -366,12 +370,12 @@ module.exports = function (appConfig, onTerminate) {
366
370
  rx.retryWhen((err$) =>
367
371
  err$.pipe(
368
372
  rx.tap((err) => logger.error({ err }, 'monitor.stats')),
369
- rx.delay(10e3)
370
- )
373
+ rx.delay(10e3),
374
+ ),
371
375
  ),
372
376
  rx.startWith({}),
373
377
  rx.publishReplay(1),
374
- rx.refCount()
378
+ rx.refCount(),
375
379
  )
376
380
 
377
381
  monitorProviders.stats$ = stats$
@@ -390,7 +394,7 @@ module.exports = function (appConfig, onTerminate) {
390
394
  heap: v8.getHeapStatistics(),
391
395
  ...stats,
392
396
  },
393
- 'STATS'
397
+ 'STATS',
394
398
  )
395
399
  elu1 = elu2
396
400
  }
@@ -419,7 +423,7 @@ module.exports = function (appConfig, onTerminate) {
419
423
  })
420
424
  .pipe(
421
425
  rx.catchError((err) => rxjs.of({ warnings: [err.message] })),
422
- rx.repeatWhen(() => rxjs.timer(10e3))
426
+ rx.repeatWhen(() => rxjs.timer(10e3)),
423
427
  )
424
428
  } else if (appConfig.status && typeof appConfig.status === 'object') {
425
429
  status$ = rxjs.timer(0, 10e3).pipe(rx.exhaustMap(() => appConfig.status))
@@ -445,7 +449,7 @@ module.exports = function (appConfig, onTerminate) {
445
449
  }),
446
450
  rx.startWith([]),
447
451
  rx.distinctUntilChanged(fp.isEqual),
448
- rx.repeatWhen((complete$) => complete$.pipe(rx.delay(10e3)))
452
+ rx.repeatWhen((complete$) => complete$.pipe(rx.delay(10e3))),
449
453
  ),
450
454
  toobusy
451
455
  ? rxjs.timer(0, 1e3).pipe(
@@ -459,10 +463,10 @@ module.exports = function (appConfig, onTerminate) {
459
463
  msg: `lag: ${toobusy.lag()}`,
460
464
  },
461
465
  ]
462
- : []
466
+ : [],
463
467
  ),
464
468
  rx.startWith([]),
465
- rx.distinctUntilChanged(fp.isEqual)
469
+ rx.distinctUntilChanged(fp.isEqual),
466
470
  )
467
471
  : rxjs.of({}),
468
472
  couch
@@ -482,7 +486,7 @@ module.exports = function (appConfig, onTerminate) {
482
486
  }
483
487
  }),
484
488
  rx.startWith([]),
485
- rx.distinctUntilChanged(fp.isEqual)
489
+ rx.distinctUntilChanged(fp.isEqual),
486
490
  )
487
491
  : rxjs.of({}),
488
492
  ds
@@ -559,7 +563,7 @@ module.exports = function (appConfig, onTerminate) {
559
563
  }
560
564
 
561
565
  return messages
562
- })
566
+ }),
563
567
  )
564
568
  .subscribe(o)
565
569
 
@@ -570,7 +574,7 @@ module.exports = function (appConfig, onTerminate) {
570
574
  }).pipe(rx.startWith([]), rx.distinctUntilChanged(fp.isEqual))
571
575
  : rxjs.of({}),
572
576
  rxjs.timer(0, 10e3),
573
- ].filter(Boolean)
577
+ ].filter(Boolean),
574
578
  )
575
579
  .pipe(
576
580
  rx.auditTime(1e3),
@@ -594,7 +598,7 @@ module.exports = function (appConfig, onTerminate) {
594
598
  ...message,
595
599
  message: undefined,
596
600
  msg: message.message,
597
- }
601
+ },
598
602
  )
599
603
  .map((message) =>
600
604
  message.id
@@ -602,9 +606,9 @@ module.exports = function (appConfig, onTerminate) {
602
606
  : {
603
607
  ...message,
604
608
  id: hashString(
605
- [message.msg, message].find(fp.isString) ?? JSON.stringify(message)
609
+ [message.msg, message].find(fp.isString) ?? JSON.stringify(message),
606
610
  ),
607
- }
611
+ },
608
612
  )
609
613
 
610
614
  return { ...status, messages, timestamp: Date.now() }
@@ -619,7 +623,7 @@ module.exports = function (appConfig, onTerminate) {
619
623
  rx.startWith({}),
620
624
  rx.distinctUntilChanged(fp.isEqual),
621
625
  rx.publishReplay(1),
622
- rx.refCount()
626
+ rx.refCount(),
623
627
  )
624
628
 
625
629
  const loggerSubscription = status$
@@ -648,21 +652,15 @@ module.exports = function (appConfig, onTerminate) {
648
652
  const { isMainThread } = require('node:worker_threads')
649
653
 
650
654
  if (isMainThread) {
651
- const os = require('os')
652
- const rx = require('rxjs/operators')
653
-
654
- const containerId = appConfig.containerId ?? os.hostname()
655
- const hostname = process.env.NODE_ENV === 'production' ? containerId : serviceName
656
-
657
655
  const unprovide = ds.record.provide(`^([^:]+):monitor\\.([^?]+)[?]?`, (key) => {
658
656
  const [, id, prop] = key.match(/^([^:]+):monitor\.([^?]+)[?]?/)
659
657
 
660
658
  if (id === serviceName) {
661
659
  // TODO (fix): If id === serviceName check if there are multiple instances.
662
- return monitorProviders[prop + '$']?.pipe(rx.map((value) => ({ [hostname]: value })))
660
+ return monitorProviders[prop + '$']
663
661
  }
664
662
 
665
- if (id === hostname) {
663
+ if (id === serviceInstanceId) {
666
664
  return monitorProviders[prop + '$']
667
665
  }
668
666
  })
@@ -750,13 +748,13 @@ module.exports = function (appConfig, onTerminate) {
750
748
  },
751
749
  ]
752
750
  .flat()
753
- .filter(Boolean)
751
+ .filter(Boolean),
754
752
  )
755
753
 
756
754
  server = createServer(
757
755
  typeof appConfig.http === 'object' ? appConfig.http : {},
758
756
  { ds, couch, config: httpConfig, logger },
759
- middleware
757
+ middleware,
760
758
  )
761
759
 
762
760
  if (httpConfig.keepAlive != null) {
@@ -794,7 +792,9 @@ module.exports = function (appConfig, onTerminate) {
794
792
  tracer: trace,
795
793
  userAgent,
796
794
  serviceName,
795
+ serviceModule,
797
796
  serviceVersion,
797
+ serviceInstanceId,
798
798
  signal: ac.signal,
799
799
  }
800
800
  }
package/errors.js CHANGED
@@ -3,8 +3,8 @@ const fp = require('lodash/fp.js')
3
3
  const { toString } = Object.prototype
4
4
 
5
5
  module.exports.AbortError = class AbortError extends Error {
6
- constructor() {
7
- super('The operation was aborted')
6
+ constructor(message) {
7
+ super(message ?? 'The operation was aborted')
8
8
  this.code = 'ABORT_ERR'
9
9
  this.name = 'AbortError'
10
10
  }
@@ -34,7 +34,7 @@ module.exports.parseError = function parseError(error) {
34
34
  {
35
35
  ...properties,
36
36
  cause: cause ? parseError(error.cause) : undefined,
37
- }
37
+ },
38
38
  )
39
39
  }
40
40
 
@@ -101,7 +101,7 @@ module.exports.serializeError = function serializeError(error) {
101
101
  data,
102
102
  cause,
103
103
  errors,
104
- })
104
+ }),
105
105
  )
106
106
  }
107
107
 
@@ -115,7 +115,7 @@ module.exports.makeMessages = function makeMessages(error, options) {
115
115
  return fp.pipe(
116
116
  fp.flattenDeep,
117
117
  fp.flatMap((x) => makeMessages(x, null)),
118
- fp.uniqBy('id')
118
+ fp.uniqBy('id'),
119
119
  )(error)
120
120
  } else if (Array.isArray(error.messages)) {
121
121
  return makeMessages(error.messages, null)
@@ -127,11 +127,11 @@ module.exports.makeMessages = function makeMessages(error, options) {
127
127
  const level = parseInt(error.level) || options?.level || 50
128
128
  const code =
129
129
  [error?.code, options?.codes?.[error?.code]].find(
130
- (x) => typeof x === 'string' && x.length > 0
130
+ (x) => typeof x === 'string' && x.length > 0,
131
131
  ) ?? undefined
132
132
  const msg =
133
133
  [error.msg, error.message, code?.toLowerCase().replace('_', ' ')].find(
134
- (x) => typeof x === 'string' && x.length > 0
134
+ (x) => typeof x === 'string' && x.length > 0,
135
135
  ) || 'unknown error'
136
136
 
137
137
  let data = error.data
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "14.2.1",
3
+ "version": "15.0.0",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "files": [
@@ -8,6 +8,7 @@
8
8
  "ass.js",
9
9
  "rxjs/*",
10
10
  "util/*",
11
+ "undici/*",
11
12
  "subtract-ranges.js",
12
13
  "serializers.js",
13
14
  "elasticsearch.js",
@@ -22,9 +23,7 @@
22
23
  "app.js",
23
24
  "errors.js",
24
25
  "worker.js",
25
- "proxy.js",
26
26
  "stream.js",
27
- "undici.js",
28
27
  "timeline.js",
29
28
  "docker-secrets.js"
30
29
  ],
@@ -71,6 +70,7 @@
71
70
  "/__tests__"
72
71
  ],
73
72
  "dependencies": {
73
+ "cache-control-parser": "^2.0.4",
74
74
  "date-fns": "^2.29.3",
75
75
  "fast-querystring": "^1.1.1",
76
76
  "hasha": "^5.2.2",
@@ -78,6 +78,7 @@
78
78
  "json5": "^2.2.3",
79
79
  "koa-compose": "^4.1.0",
80
80
  "lodash": "^4.17.21",
81
+ "lru-cache": "^10.0.1",
81
82
  "mime": "^3.0.0",
82
83
  "moment-timezone": "^0.5.43",
83
84
  "nconf": "^0.12.0",
@@ -90,23 +91,25 @@
90
91
  "smpte-timecode": "^1.3.3",
91
92
  "split-string": "^6.0.0",
92
93
  "toobusy-js": "^0.5.1",
93
- "undici": "^5.22.0",
94
+ "undici": "^5.25.2",
94
95
  "url-join": "^4.0.0",
95
96
  "xuid": "^4.1.2"
96
97
  },
97
98
  "devDependencies": {
98
- "eslint": "^8.38.0",
99
- "eslint-config-prettier": "^8.8.0",
99
+ "@types/node": "^20.6.3",
100
+ "eslint": "^8.50.0",
101
+ "eslint-config-prettier": "^9.0.0",
100
102
  "eslint-config-standard": "^17.0.0",
101
- "eslint-plugin-import": "^2.27.5",
102
- "eslint-plugin-n": "^15.7.0",
103
+ "eslint-plugin-import": "^2.28.1",
104
+ "eslint-plugin-n": "^16.1.0",
103
105
  "eslint-plugin-node": "^11.1.0",
104
106
  "eslint-plugin-promise": "^6.0.0",
105
107
  "husky": "^8.0.3",
106
- "lint-staged": "^13.2.1",
108
+ "lint-staged": "^14.0.1",
107
109
  "pinst": "^3.0.0",
108
- "prettier": "^2.8.7",
110
+ "prettier": "^3.0.3",
109
111
  "rxjs": "^7.5.6",
112
+ "send": "^0.18.0",
110
113
  "tap": "^16.3.4"
111
114
  },
112
115
  "peerDependencies": {
@@ -0,0 +1,192 @@
1
+ const assert = require('assert')
2
+ const createError = require('http-errors')
3
+ const xuid = require('xuid')
4
+ const undici = require('undici')
5
+ const stream = require('stream')
6
+ const { parseHeaders } = require('../http')
7
+
8
+ class Readable extends stream.Readable {
9
+ constructor({ statusCode, statusMessage, headers, ...opts }) {
10
+ super(opts)
11
+ this.statusCode = statusCode
12
+ this.statusMessage = statusMessage
13
+ this.headers = headers
14
+ this.body = this
15
+ }
16
+
17
+ async text() {
18
+ const dec = new TextDecoder()
19
+ let str = ''
20
+ for await (const chunk of this) {
21
+ if (typeof chunk === 'string') {
22
+ str += chunk
23
+ } else {
24
+ str += dec.decode(chunk, { stream: true })
25
+ }
26
+ }
27
+ // Flush the streaming TextDecoder so that any pending
28
+ // incomplete multibyte characters are handled.
29
+ str += dec.decode(undefined, { stream: false })
30
+ return str
31
+ }
32
+
33
+ async json() {
34
+ return JSON.parse(await this.text())
35
+ }
36
+
37
+ async arrayBuffer() {
38
+ const buffers = []
39
+ for await (const chunk of this) {
40
+ buffers.push(chunk)
41
+ }
42
+ return Buffer.concat(buffers)
43
+ }
44
+
45
+ async buffer() {
46
+ return Buffer.from(await this.arrayBuffer())
47
+ }
48
+
49
+ async dump() {
50
+ let n = 0
51
+ try {
52
+ for await (const chunk of this) {
53
+ // do nothing
54
+ n += chunk.length
55
+ if (n > 128 * 1024) {
56
+ break
57
+ }
58
+ }
59
+ } catch {
60
+ this.destroy()
61
+ }
62
+ }
63
+ }
64
+
65
+ const dispatchers = {
66
+ abort: require('./interceptor/abort.js'),
67
+ catch: require('./interceptor/catch.js'),
68
+ content: require('./interceptor/content.js'),
69
+ responseBodyDump: require('./interceptor/response-body-dump.js'),
70
+ log: require('./interceptor/log.js'),
71
+ redirect: require('./interceptor/redirect.js'),
72
+ responseBodyRetry: require('./interceptor/response-body-retry.js'),
73
+ responseStatusRetry: require('./interceptor/response-status-retry.js'),
74
+ responseRetry: require('./interceptor/response-retry.js'),
75
+ signal: require('./interceptor/signal.js'),
76
+ proxy: require('./interceptor/proxy.js'),
77
+ }
78
+
79
+ async function request(urlOrOpts, opts = {}) {
80
+ let url
81
+ if (typeof urlOrOpts === 'string') {
82
+ url = new URL(urlOrOpts)
83
+ } else if (urlOrOpts instanceof URL) {
84
+ url = urlOrOpts
85
+ } else if (typeof urlOrOpts?.origin === 'string' && typeof urlOrOpts?.path === 'string') {
86
+ url = urlOrOpts
87
+ } else if (typeof urlOrOpts === 'object' && urlOrOpts != null) {
88
+ opts = urlOrOpts
89
+ url = opts.url
90
+ }
91
+
92
+ const method = opts.method ?? (opts.body ? 'POST' : 'GET')
93
+ const idempotent = opts.idempotent ?? (method === 'GET' || method === 'HEAD')
94
+ const dump = opts.dump ?? method === 'HEAD'
95
+
96
+ let headers
97
+ if (Array.isArray(opts.headers)) {
98
+ headers = parseHeaders(opts.headers)
99
+ } else {
100
+ headers = opts.headers
101
+ }
102
+
103
+ opts = {
104
+ url,
105
+ method,
106
+ body: opts.body,
107
+ headers: {
108
+ 'request-id': xuid(),
109
+ 'user-agent': opts.userAgent ?? globalThis.userAgent,
110
+ ...headers,
111
+ },
112
+ origin: opts.origin ?? url.origin,
113
+ path: opts.path ?? url.search ? `${url.pathname}${url.search ?? ''}` : url.pathname,
114
+ reset: opts.reset ?? false,
115
+ headersTimeout: opts.headersTimeout,
116
+ bodyTimeout: opts.bodyTimeout,
117
+ idempotent,
118
+ signal: opts.signal,
119
+ retry: opts.retry ?? 8,
120
+ follow: { count: opts.maxRedirections ?? 8, ...opts.redirect, ...opts.follow },
121
+ dump,
122
+ logger: opts.logger,
123
+ }
124
+
125
+ const dispatcher = opts.dispatcher ?? undici.getGlobalDispatcher()
126
+
127
+ return new Promise((resolve) => {
128
+ let dispatch = (opts, handler) => dispatcher.dispatch(opts, handler)
129
+
130
+ dispatch = dispatchers.catch(dispatch)
131
+ dispatch = dispatchers.abort(dispatch)
132
+ dispatch = dispatchers.log(dispatch)
133
+ dispatch = dispatchers.responseRetry(dispatch)
134
+ dispatch = dispatchers.responseStatusRetry(dispatch)
135
+ dispatch = dispatchers.responseBodyRetry(dispatch)
136
+ dispatch = dispatchers.content(dispatch)
137
+ dispatch = dispatchers.responseBodyDump(dispatch)
138
+ dispatch = dispatchers.redirect(dispatch)
139
+ dispatch = dispatchers.signal(dispatch)
140
+ dispatch = dispatchers.proxy(dispatch)
141
+
142
+ dispatch(opts, {
143
+ resolve,
144
+ /** @type {Function | null} */ abort: null,
145
+ /** @type {stream.Readable | null} */ body: null,
146
+ onConnect(abort) {
147
+ this.abort = abort
148
+ },
149
+ onHeaders(statusCode, rawHeaders, resume, statusMessage) {
150
+ assert(this.abort)
151
+
152
+ const headers = parseHeaders(rawHeaders)
153
+
154
+ if (statusCode >= 400) {
155
+ this.abort(createError(statusCode, { headers }))
156
+ } else {
157
+ assert(statusCode >= 200)
158
+
159
+ this.body = new Readable({
160
+ read: resume,
161
+ highWaterMark: 128 * 1024,
162
+ statusCode,
163
+ statusMessage,
164
+ headers,
165
+ })
166
+
167
+ this.resolve(this.body)
168
+ this.resolve = null
169
+ }
170
+
171
+ return false
172
+ },
173
+ onData(chunk) {
174
+ assert(this.body)
175
+ return this.body.push(chunk)
176
+ },
177
+ onComplete() {
178
+ assert(this.body)
179
+ this.body.push(null)
180
+ },
181
+ onError(err) {
182
+ if (this.body) {
183
+ this.body.destroy(err)
184
+ } else {
185
+ this.resolve(Promise.reject(err))
186
+ }
187
+ },
188
+ })
189
+ })
190
+ }
191
+
192
+ module.exports = { request }
@@ -0,0 +1,61 @@
1
+ const { AbortError } = require('../../errors')
2
+
3
+ class Handler {
4
+ constructor(opts, { handler }) {
5
+ this.handler = handler
6
+ this.pos = 0
7
+ this.reason = null
8
+ }
9
+
10
+ onConnect(abort) {
11
+ this.abort = abort
12
+ this.handler.onConnect((reason) => {
13
+ this.reason = reason ?? new AbortError()
14
+ })
15
+ }
16
+
17
+ onBodySent(chunk) {
18
+ return this.handler.onBodySent(chunk)
19
+ }
20
+
21
+ onHeaders(statusCode, rawHeaders, resume, statusMessage) {
22
+ if (this.reason == null) {
23
+ const ret = this.handler.onHeaders(statusCode, rawHeaders, resume, statusMessage)
24
+ if (this.reason == null) {
25
+ return ret
26
+ }
27
+ }
28
+
29
+ return true
30
+ }
31
+
32
+ onData(chunk) {
33
+ if (this.reason == null) {
34
+ const ret = this.handler.onData(chunk)
35
+ if (this.reason == null) {
36
+ return ret
37
+ }
38
+ }
39
+
40
+ this.pos += chunk.length
41
+ if (this.pos < 128 * 1024) {
42
+ return true
43
+ }
44
+
45
+ this.abort(this.reason)
46
+
47
+ return false
48
+ }
49
+
50
+ onComplete(rawTrailers) {
51
+ return this.reason == null
52
+ ? this.handler.onComplete(rawTrailers)
53
+ : this.handler.onError(this.reason)
54
+ }
55
+
56
+ onError(err) {
57
+ return this.handler.onError(err)
58
+ }
59
+ }
60
+
61
+ module.exports = (dispatch) => (opts, handler) => dispatch(opts, new Handler(opts, { handler }))
@@ -0,0 +1,55 @@
1
+ class Handler {
2
+ constructor(opts, { handler }) {
3
+ this.handler = handler
4
+ }
5
+
6
+ onConnect(abort) {
7
+ this.abort = abort
8
+ try {
9
+ return this.handler.onConnect(abort)
10
+ } catch (err) {
11
+ this.abort(err)
12
+ }
13
+ }
14
+
15
+ onBodySent(chunk) {
16
+ try {
17
+ return this.handler.onBodySent(chunk)
18
+ } catch (err) {
19
+ this.abort(err)
20
+ }
21
+ }
22
+
23
+ onHeaders(statusCode, rawHeaders, resume, statusMessage) {
24
+ try {
25
+ return this.handler.onHeaders(statusCode, rawHeaders, resume, statusMessage)
26
+ } catch (err) {
27
+ this.abort(err)
28
+ return false
29
+ }
30
+ }
31
+
32
+ onData(chunk) {
33
+ try {
34
+ return this.handler.onData(chunk)
35
+ } catch (err) {
36
+ this.abort(err)
37
+ return false
38
+ }
39
+ }
40
+
41
+ onComplete(rawTrailers) {
42
+ try {
43
+ return this.handler.onComplete(rawTrailers)
44
+ } catch (err) {
45
+ this.abort(err)
46
+ return false
47
+ }
48
+ }
49
+
50
+ onError(err) {
51
+ return this.handler.onError(err)
52
+ }
53
+ }
54
+
55
+ module.exports = (dispatch) => (opts, handler) => dispatch(opts, new Handler(opts, { handler }))