@nxtedition/lib 19.8.1 → 19.8.2

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 (3) hide show
  1. package/couch.js +51 -153
  2. package/package.json +16 -14
  3. package/weakCache.d.ts +4 -0
package/couch.js CHANGED
@@ -9,7 +9,7 @@ import urljoin from 'url-join'
9
9
  import undici, { util as undiciUtil } from 'undici'
10
10
  import { AbortError } from './errors.js'
11
11
  import split2 from 'split2'
12
- import { parse as parseContentType } from 'content-type'
12
+ import { interceptors } from '@nxtedition/nxt-undici'
13
13
 
14
14
  // https://github.com/fastify/fastify/blob/main/lib/reqIdGenFactory.js
15
15
  // 2,147,483,647 (2^31 − 1) stands for max SMI value (an internal optimization of V8).
@@ -887,141 +887,6 @@ function _normalizeAllDocsOptions({
887
887
  }
888
888
  }
889
889
 
890
- class SignalHandler extends undici.DecoratorHandler {
891
- #signal
892
- #handler
893
- #abort
894
-
895
- constructor({ signal, handler }) {
896
- super(handler)
897
- this.#signal = signal
898
- this.#handler = handler
899
- }
900
-
901
- onConnect(abort) {
902
- if (this.#signal?.aborted) {
903
- abort(this.#signal.reason)
904
- } else {
905
- if (this.#signal) {
906
- this.#abort = () => abort(this.#signal.reason)
907
- this.#signal.addEventListener('abort', this.#abort)
908
- }
909
- this.#handler.onConnect?.(abort)
910
- }
911
- }
912
-
913
- onComplete(...args) {
914
- this.#signal?.removeEventListener('abort', this.#abort)
915
- this.#handler.onComplete?.(...args)
916
- }
917
-
918
- onError(...args) {
919
- this.#signal?.removeEventListener('abort', this.#abort)
920
- this.#handler.onError?.(...args)
921
- }
922
- }
923
-
924
- class ErrorHandler extends undici.DecoratorHandler {
925
- #str
926
- #decoder
927
- #statusCode
928
- #contentType
929
- #opts
930
- #handler
931
- #error
932
- #headers
933
-
934
- constructor({ opts, handler }) {
935
- super(handler)
936
-
937
- this.#handler = handler
938
- this.#opts = opts
939
- }
940
-
941
- onConnect(...args) {
942
- this.#str = ''
943
- this.#decoder = null
944
- this.#handler.onConnect?.(...args)
945
- }
946
-
947
- onHeaders(statusCode, headers, resume, statusText) {
948
- this.#statusCode = statusCode
949
-
950
- if (this.#statusCode < 200 || this.#statusCode > 300) {
951
- this.#headers = Array.isArray(headers) ? undiciUtil.parseHeaders(headers) : headers
952
-
953
- this.#error = new Error(statusText ?? statusCode)
954
-
955
- this.#contentType = this.#headers['content-type']
956
- ? parseContentType(this.#headers['content-type'] ?? '')?.type
957
- : null
958
-
959
- if (this.#contentType !== 'application/json' && this.#contentType !== 'plain/text') {
960
- throw this.#error
961
- }
962
-
963
- this.#decoder = new TextDecoder()
964
- } else {
965
- return this.#handler.onHeaders?.(statusCode, headers, resume, statusText)
966
- }
967
- }
968
-
969
- onData(data) {
970
- if (this.#error) {
971
- this.#str += this.#decoder?.decode(data, { stream: true }) ?? ''
972
- } else {
973
- return this.#handler?.onData(data)
974
- }
975
- }
976
-
977
- onComplete(...args) {
978
- if (this.#error) {
979
- this.#str += this.#decoder?.decode(undefined, { stream: false }) ?? ''
980
-
981
- if (this.#contentType === 'application/json') {
982
- let body
983
- let reason
984
- let error
985
- try {
986
- body = JSON.parse(this.#str)
987
- reason = body.reason
988
- error = body.error
989
- } catch {
990
- body = this.#str
991
- // Do nothing...
992
- }
993
-
994
- throw Object.assign(this.#error, {
995
- reason,
996
- error,
997
- data: {
998
- req: this.#opts,
999
- res: {
1000
- body,
1001
- statusCode: this.#statusCode,
1002
- },
1003
- },
1004
- })
1005
- } else if (this.#contentType === 'plain/text') {
1006
- throw Object.assign(this.#error, {
1007
- data: {
1008
- ureq: this.#opts,
1009
- ures: {
1010
- body: this.#str,
1011
- statusCode: this.#statusCode,
1012
- headers: this.#headers,
1013
- },
1014
- },
1015
- })
1016
- }
1017
-
1018
- assert(false)
1019
- } else {
1020
- this.#handler.onComplete?.(...args)
1021
- }
1022
- }
1023
- }
1024
-
1025
890
  class StreamOutput extends stream.Readable {
1026
891
  #str
1027
892
  #resume
@@ -1036,8 +901,8 @@ class StreamOutput extends stream.Readable {
1036
901
  ttfb: -1,
1037
902
  }
1038
903
 
1039
- constructor({ highWaterMark = 256 }) {
1040
- super({ objectMode: true, highWaterMark })
904
+ constructor({ signal, highWaterMark = 256 }) {
905
+ super({ objectMode: true, highWaterMark, signal })
1041
906
  }
1042
907
 
1043
908
  get headers() {
@@ -1136,6 +1001,8 @@ class PromiseOutput {
1136
1001
  #decoder
1137
1002
  #headers
1138
1003
  #startTime = performance.now()
1004
+ #signal
1005
+ #abort
1139
1006
  #stats = {
1140
1007
  connect: -1,
1141
1008
  headers: -1,
@@ -1144,15 +1011,23 @@ class PromiseOutput {
1144
1011
  error: -1,
1145
1012
  }
1146
1013
 
1147
- constructor({ resolve, reject }) {
1014
+ constructor({ resolve, reject, signal }) {
1148
1015
  this.#resolve = resolve
1149
1016
  this.#reject = reject
1017
+ this.#signal = signal
1150
1018
  }
1151
1019
 
1152
- onConnect() {
1020
+ onConnect(abort) {
1153
1021
  this.#stats.connect = performance.now() - this.#startTime
1154
1022
  this.#decoder = new TextDecoder()
1155
1023
  this.#str = ''
1024
+
1025
+ if (this.#signal?.aborted) {
1026
+ abort()
1027
+ } else {
1028
+ this.#abort = abort
1029
+ this.#signal?.addEventListener('abort', this.#abort)
1030
+ }
1156
1031
  }
1157
1032
 
1158
1033
  onHeaders(statusCode, rawHeaders, resume, statusText) {
@@ -1181,9 +1056,8 @@ class PromiseOutput {
1181
1056
 
1182
1057
  this.#str += this.#decoder.decode(undefined, { stream: false })
1183
1058
 
1184
- this.#resolve(
1185
- Object.assign(JSON.parse(this.#str), { headers: this.#headers, stats: this.#stats }),
1186
- )
1059
+ const val = Object.assign(JSON.parse(this.#str), { headers: this.#headers, stats: this.#stats })
1060
+ this.#onDone(null, val)
1187
1061
  }
1188
1062
 
1189
1063
  onError(err) {
@@ -1191,10 +1065,23 @@ class PromiseOutput {
1191
1065
  this.#stats.error = performance.now() - this.#startTime - this.#stats.data
1192
1066
  }
1193
1067
 
1194
- this.#reject(err)
1068
+ this.#onDone(err)
1069
+ }
1070
+
1071
+ #onDone(err, val) {
1072
+ if (err) {
1073
+ this.#reject(err)
1074
+ } else {
1075
+ this.#resolve(val)
1076
+ }
1077
+
1078
+ if (this.#abort) {
1079
+ this.#signal?.removeEventListener('abort', this.#abort)
1080
+ }
1195
1081
  }
1196
1082
  }
1197
1083
 
1084
+ const dispatcherCache = new WeakMap()
1198
1085
  export function request(
1199
1086
  url,
1200
1087
  {
@@ -1204,6 +1091,7 @@ export function request(
1204
1091
  headers,
1205
1092
  dispatcher = undici.getGlobalDispatcher(),
1206
1093
  signal,
1094
+ logger,
1207
1095
  stream,
1208
1096
  },
1209
1097
  ) {
@@ -1221,26 +1109,36 @@ export function request(
1221
1109
  headers: {
1222
1110
  'content-type': body != null && typeof body === 'object' ? 'application/json' : 'plain/text',
1223
1111
  'user-agent': globalThis.userAgent ?? 'nxt-lib',
1224
- 'request-id': genReqId(),
1225
1112
  accept: 'application/json',
1226
1113
  ...headers,
1227
1114
  },
1115
+ logger,
1228
1116
  body: body != null && typeof body === 'object' ? JSON.stringify(body) : body,
1229
1117
  }
1230
1118
 
1231
- dispatcher = dispatcher.compose(
1232
- (dispatch) => (opts, handler) => dispatch(opts, new ErrorHandler({ opts, handler })),
1233
- (dispatch) => (opts, handler) => dispatch(opts, new SignalHandler({ signal, handler })),
1234
- )
1119
+ let wrappedDispatcher = dispatcherCache.get(dispatcher)
1120
+ if (!wrappedDispatcher) {
1121
+ wrappedDispatcher = dispatcher.compose(
1122
+ interceptors.responseError,
1123
+ interceptors.log,
1124
+ interceptors.requestId,
1125
+ interceptors.responseRetry,
1126
+ interceptors.responseVerify,
1127
+ interceptors.redirect,
1128
+ interceptors.cache,
1129
+ interceptors.proxy,
1130
+ )
1131
+ dispatcherCache.set(dispatcher, wrappedDispatcher)
1132
+ }
1235
1133
 
1236
1134
  if (stream) {
1237
- const handler = new StreamOutput(stream)
1238
- dispatcher.dispatch(opts, handler)
1135
+ const handler = new StreamOutput({ signal, ...stream })
1136
+ wrappedDispatcher.dispatch(opts, handler)
1239
1137
  return handler
1240
1138
  } else {
1241
1139
  return new Promise((resolve, reject) => {
1242
- const handler = new PromiseOutput({ resolve, reject })
1243
- dispatcher.dispatch(opts, handler)
1140
+ const handler = new PromiseOutput({ resolve, reject, signal })
1141
+ wrappedDispatcher.dispatch(opts, handler)
1244
1142
  })
1245
1143
  }
1246
1144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "19.8.1",
3
+ "version": "19.8.2",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",
@@ -26,6 +26,7 @@
26
26
  "timers.js",
27
27
  "trace.js",
28
28
  "weakCache.js",
29
+ "weakCache.d.ts",
29
30
  "couch.js",
30
31
  "app.js",
31
32
  "errors.js",
@@ -74,13 +75,14 @@
74
75
  }
75
76
  },
76
77
  "eslintIgnore": [
77
- "/__tests__"
78
+ "/__tests__",
79
+ "**/*.d.ts"
78
80
  ],
79
81
  "dependencies": {
80
- "@aws-sdk/client-s3": "^3.554.0",
82
+ "@aws-sdk/client-s3": "^3.596.0",
81
83
  "@elastic/elasticsearch": "^8.13.1",
82
- "@elastic/transport": "^8.5.1",
83
- "@nxtedition/nxt-undici": "^2.0.46",
84
+ "@elastic/transport": "^8.6.0",
85
+ "@nxtedition/nxt-undici": "^2.2.5",
84
86
  "content-type": "^1.0.5",
85
87
  "date-fns": "^3.6.0",
86
88
  "fast-querystring": "^1.1.1",
@@ -95,31 +97,31 @@
95
97
  "nested-error-stacks": "^2.1.1",
96
98
  "object-hash": "^3.0.0",
97
99
  "p-queue": "^8.0.1",
98
- "pino": "^8.20.0",
100
+ "pino": "^9.2.0",
99
101
  "qs": "^6.12.1",
100
102
  "request-target": "^1.0.2",
101
103
  "smpte-timecode": "^1.3.5",
102
104
  "split-string": "^6.0.0",
103
105
  "split2": "^4.2.0",
104
106
  "toobusy-js": "^0.5.1",
105
- "undici": "^6.13.0",
107
+ "undici": "^6.18.2",
106
108
  "url-join": "^5.0.0"
107
109
  },
108
110
  "devDependencies": {
109
- "@nxtedition/deepstream.io-client-js": ">=24.1.20",
110
- "@types/lodash": "^4.17.0",
111
- "@types/node": "^20.12.7",
111
+ "@nxtedition/deepstream.io-client-js": ">=24.2.4",
112
+ "@types/lodash": "^4.17.5",
113
+ "@types/node": "^20.14.2",
112
114
  "eslint": "^8.0.0",
113
115
  "eslint-config-prettier": "^9.1.0",
114
116
  "eslint-config-standard": "^17.0.0",
115
117
  "eslint-plugin-import": "^2.29.1",
116
- "eslint-plugin-n": "^17.2.1",
118
+ "eslint-plugin-n": "^17.9.0",
117
119
  "eslint-plugin-node": "^11.1.0",
118
- "eslint-plugin-promise": "^6.0.0",
120
+ "eslint-plugin-promise": "^6.2.0",
119
121
  "husky": "^9.0.11",
120
- "lint-staged": "^15.2.2",
122
+ "lint-staged": "^15.2.7",
121
123
  "pinst": "^3.0.0",
122
- "prettier": "^3.2.5",
124
+ "prettier": "^3.3.2",
123
125
  "rxjs": "^7.5.6",
124
126
  "send": "^0.18.0"
125
127
  },
package/weakCache.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export function makeWeakCache<FactoryArgs extends any[], CachedType>(
2
+ valueSelector: (...args: FactoryArgs) => CachedType,
3
+ keySelector?: (...args: FactoryArgs) => string,
4
+ ): (...args: FactoryArgs) => CachedType