@nxtedition/lib 19.8.13 → 19.8.15

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 (2) hide show
  1. package/couch.js +173 -148
  2. package/package.json +7 -7
package/couch.js CHANGED
@@ -7,7 +7,13 @@ import tp from 'timers/promises'
7
7
  import { defaultDelay as delay } from './http.js'
8
8
  import urljoin from 'url-join'
9
9
  import { AbortError } from './errors.js'
10
- import { dispatch, Agent, Pool, parseHeaders } from '@nxtedition/nxt-undici'
10
+ import {
11
+ dispatch,
12
+ Agent,
13
+ Pool,
14
+ parseHeaders,
15
+ request as undiciRequest,
16
+ } from '@nxtedition/nxt-undici'
11
17
 
12
18
  // https://github.com/fastify/fastify/blob/main/lib/reqIdGenFactory.js
13
19
  // 2,147,483,647 (2^31 − 1) stands for max SMI value (an internal optimization of V8).
@@ -191,12 +197,6 @@ export function makeCouch(opts) {
191
197
  throw new Error('invalid pathname')
192
198
  }
193
199
 
194
- const batched = options.batched || false
195
- const live = options.live == null || !!options.live
196
- const retry = options.retry
197
-
198
- let retryCount = 0
199
-
200
200
  const ac = new AbortController()
201
201
  const onAbort = () => {
202
202
  ac.abort()
@@ -214,169 +214,192 @@ export function makeCouch(opts) {
214
214
  }
215
215
  }
216
216
 
217
- let remaining = Number(options.limit) || Infinity
217
+ const batched = options.batched || false
218
+ const live = options.live == null || !!options.live
219
+ const retry = options.retry
220
+ const limit = options.limit
221
+
218
222
  try {
219
- while (true) {
220
- let src
221
- try {
222
- const query = { ...params, feed: live ? 'continuous' : 'normal' }
223
+ yield* _changes({
224
+ batched,
225
+ live,
226
+ retry,
227
+ limit,
228
+ params,
229
+ method,
230
+ body,
231
+ signal: ac.signal,
232
+ client,
233
+ })
234
+ } finally {
235
+ ac.abort()
236
+ if (signal) {
237
+ if (signal.off) {
238
+ signal.off('abort', onAbort)
239
+ } else if (signal.removeEventListener) {
240
+ signal.removeEventListener('abort', onAbort)
241
+ }
242
+ }
243
+ }
244
+ }
223
245
 
224
- if (Number.isFinite(remaining)) {
225
- query.limit = remaining
226
- }
246
+ async function* _changes({ batched, live, retry, limit, params, method, body, signal, client }) {
247
+ let retryCount = 0
248
+ let remaining = Number(limit) || Infinity
249
+ while (true) {
250
+ let src
251
+ try {
252
+ const query = { ...params, feed: live ? 'continuous' : 'normal' }
227
253
 
228
- const ureq = {
229
- path: `${dbPathname}/_changes`,
230
- query,
231
- idempotent: false,
232
- blocking: true,
233
- method,
234
- body: JSON.stringify(body),
235
- signal: ac.signal,
236
- headers: {
237
- 'user-agent': userAgent,
238
- 'request-id': genReqId(),
239
- ...(body ? { 'content-type': 'application/json' } : {}),
240
- },
241
- bodyTimeout: 2 * (params.heartbeat || 60e3),
242
- }
254
+ if (Number.isFinite(remaining)) {
255
+ query.limit = remaining
256
+ }
243
257
 
244
- const ures = await client.request(ureq)
258
+ const ureq = {
259
+ path: `${dbPathname}/_changes`,
260
+ origin: dbOrigin,
261
+ query,
262
+ idempotent: false,
263
+ blocking: true,
264
+ method,
265
+ body: JSON.stringify(body),
266
+ signal,
267
+ headers: {
268
+ 'user-agent': userAgent,
269
+ 'request-id': genReqId(),
270
+ ...(body ? { 'content-type': 'application/json' } : {}),
271
+ },
272
+ bodyTimeout: 2 * (params.heartbeat || 60e3),
273
+ highWaterMark: 256 * 1024,
274
+ dispatcher: client,
275
+ }
245
276
 
246
- if (ures.statusCode < 200 || ures.statusCode >= 300) {
247
- throw makeError(ureq, {
248
- status: ures.statusCode,
249
- headers: ures.headers,
250
- data: await ures.body.text(),
251
- })
252
- }
277
+ const ures = await undiciRequest(ureq)
253
278
 
254
- src = ures.body
279
+ if (ures.statusCode < 200 || ures.statusCode >= 300) {
280
+ throw makeError(ureq, {
281
+ status: ures.statusCode,
282
+ headers: ures.headers,
283
+ data: await ures.body.text(),
284
+ })
285
+ }
255
286
 
256
- const changes = []
287
+ src = ures.body
257
288
 
258
- let resume = null
259
- let error = null
260
- let ended = false
261
- let state = 0
289
+ const changes = []
262
290
 
263
- function maybeResume() {
264
- if (resume) {
265
- resume()
266
- resume = null
267
- }
291
+ let resume = null
292
+ let error = null
293
+ let ended = false
294
+ let state = 0
295
+
296
+ function maybeResume() {
297
+ if (resume) {
298
+ resume()
299
+ resume = null
268
300
  }
301
+ }
269
302
 
270
- src
271
- .on('readable', maybeResume)
272
- .on('error', (err) => {
273
- error = err
274
- maybeResume()
275
- })
276
- .on('end', () => {
277
- ended = true
278
- maybeResume()
279
- })
280
- .on('close', maybeResume)
281
-
282
- let str = ''
283
- while (true) {
284
- const chunk = src.read()
285
-
286
- if (chunk !== null) {
287
- const lines = (str + chunk).split(/\r?\n/)
288
- str = lines.pop() ?? ''
289
-
290
- for (const line of lines) {
291
- if (line === '') {
292
- // hearbeat
293
- yield batched ? [] : null
294
- } else if (line === ',') {
295
- // Do nothing. Couch sometimes insert new line between
296
- // json body and comma.
297
- } else if (live) {
298
- const data = JSON.parse(line)
299
- if (data.last_seq) {
300
- params.since = data.last_seq
303
+ src
304
+ .on('readable', maybeResume)
305
+ .on('error', (err) => {
306
+ error = err
307
+ maybeResume()
308
+ })
309
+ .on('end', () => {
310
+ ended = true
311
+ maybeResume()
312
+ })
313
+ .on('close', maybeResume)
314
+
315
+ let str = ''
316
+ while (true) {
317
+ const chunk = src.read()
318
+
319
+ if (chunk !== null) {
320
+ const lines = (str + chunk).split(/\r?\n/)
321
+ str = lines.pop() ?? ''
322
+
323
+ for (const line of lines) {
324
+ if (line === '') {
325
+ // hearbeat
326
+ yield batched ? [] : null
327
+ } else if (line === ',') {
328
+ // Do nothing. Couch sometimes insert new line between
329
+ // json body and comma.
330
+ } else if (live) {
331
+ const data = JSON.parse(line)
332
+ if (data.last_seq) {
333
+ params.since = data.last_seq
334
+ } else {
335
+ params.since = data.seq || params.since
336
+ changes.push(data)
337
+ }
338
+ } else {
339
+ // NOTE: This makes some assumptions about the format of the JSON.
340
+ if (state === 0) {
341
+ if (line.endsWith('[')) {
342
+ state = 1
301
343
  } else {
302
- params.since = data.seq || params.since
303
- changes.push(data)
344
+ assert(false, 'invalid head: ' + line)
304
345
  }
305
- } else {
306
- // NOTE: This makes some assumptions about the format of the JSON.
307
- if (state === 0) {
308
- if (line.endsWith('[')) {
309
- state = 1
310
- } else {
311
- assert(false, 'invalid head: ' + line)
312
- }
313
- } else if (state === 1) {
314
- if (line.startsWith(']')) {
315
- state = 2
316
- } else {
317
- const idx = line.lastIndexOf('}') + 1
318
- try {
319
- assert(idx >= 0, 'invalid row: ' + idx + ' ' + line)
320
- const change = JSON.parse(line.slice(0, idx))
321
- params.since = change.seq || params.since
322
- changes.push(change)
323
- } catch (err) {
324
- throw Object.assign(err, { data: line })
325
- }
346
+ } else if (state === 1) {
347
+ if (line.startsWith(']')) {
348
+ state = 2
349
+ } else {
350
+ const idx = line.lastIndexOf('}') + 1
351
+ try {
352
+ assert(idx >= 0, 'invalid row: ' + idx + ' ' + line)
353
+ const change = JSON.parse(line.slice(0, idx))
354
+ params.since = change.seq || params.since
355
+ changes.push(change)
356
+ } catch (err) {
357
+ throw Object.assign(err, { data: line })
326
358
  }
327
- } else if (state === 2) {
328
- state = 3
329
- params.since = JSON.parse('{' + line).last_seq
330
- assert(params.since, 'invalid trailer: ' + line)
331
359
  }
360
+ } else if (state === 2) {
361
+ state = 3
362
+ params.since = JSON.parse('{' + line).last_seq
363
+ assert(params.since, 'invalid trailer: ' + line)
332
364
  }
333
365
  }
334
- } else if (changes.length) {
335
- remaining -= changes.length
336
- assert(remaining >= 0, 'invalid remaining: ' + remaining)
366
+ }
367
+ } else if (changes.length) {
368
+ remaining -= changes.length
369
+ assert(remaining >= 0, 'invalid remaining: ' + remaining)
337
370
 
338
- if (batched) {
339
- yield changes.splice(0)
340
- } else {
341
- yield* changes.splice(0)
342
- }
343
- } else if (error) {
344
- throw error
345
- } else if (!ended) {
346
- await new Promise((resolve) => {
347
- resume = resolve
348
- })
371
+ if (batched) {
372
+ yield changes.splice(0)
349
373
  } else {
350
- return
374
+ yield* changes.splice(0)
351
375
  }
352
- }
353
- } catch (err) {
354
- if (err.name === 'AbortError') {
355
- throw err
356
- } else if (typeof retry === 'function') {
357
- const retryState = { since: params.since }
358
- Object.assign(
359
- retryState,
360
- await retry(err, retryCount++, retryState, { signal }, () =>
361
- delay(err, retryCount, { signal }),
362
- ),
363
- )
364
- params.since = retryState.since ?? 0
376
+ } else if (error) {
377
+ throw error
378
+ } else if (!ended) {
379
+ await new Promise((resolve) => {
380
+ resume = resolve
381
+ })
365
382
  } else {
366
- await delay(err, retryCount, { signal })
383
+ return
367
384
  }
368
- } finally {
369
- src?.on('error', () => {}).destroy()
370
385
  }
371
- }
372
- } finally {
373
- ac.abort()
374
- if (signal) {
375
- if (signal.off) {
376
- signal.off('abort', onAbort)
377
- } else if (signal.removeEventListener) {
378
- signal.removeEventListener('abort', onAbort)
386
+ } catch (err) {
387
+ if (err.name === 'AbortError') {
388
+ throw err
389
+ } else if (typeof retry === 'function') {
390
+ const retryState = { since: params.since }
391
+ Object.assign(
392
+ retryState,
393
+ await retry(err, retryCount++, retryState, { signal }, () =>
394
+ delay(err, retryCount, { signal }),
395
+ ),
396
+ )
397
+ params.since = retryState.since ?? 0
398
+ } else {
399
+ await delay(err, retryCount, { signal })
379
400
  }
401
+ } finally {
402
+ src?.on('error', () => {}).destroy()
380
403
  }
381
404
  }
382
405
  }
@@ -451,10 +474,11 @@ export function makeCouch(opts) {
451
474
  method,
452
475
  body: typeof body === 'object' && body ? JSON.stringify(body) : body,
453
476
  headers,
477
+ dispatcher: client,
454
478
  }
455
479
 
456
480
  return new Promise((resolve, reject) =>
457
- client.dispatch(req, {
481
+ dispatch(req, {
458
482
  resolve,
459
483
  reject,
460
484
  signal,
@@ -702,11 +726,12 @@ export function makeCouch(opts) {
702
726
  }
703
727
 
704
728
  async function up(params, body, { client = defaultClient, signal = null } = {}) {
705
- const res = await client.request({
729
+ const res = await request({
706
730
  path: '/_up',
707
731
  method: 'GET',
708
732
  signal,
709
733
  throwOnError: true,
734
+ dispatcher: client,
710
735
  })
711
736
  return await res.body.json()
712
737
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "19.8.13",
3
+ "version": "19.8.15",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",
@@ -79,10 +79,10 @@
79
79
  "**/*.d.ts"
80
80
  ],
81
81
  "dependencies": {
82
- "@aws-sdk/client-s3": "^3.606.0",
82
+ "@aws-sdk/client-s3": "^3.614.0",
83
83
  "@elastic/elasticsearch": "^8.14.0",
84
- "@elastic/transport": "^8.6.1",
85
- "@nxtedition/nxt-undici": "^4.0.1",
84
+ "@elastic/transport": "^8.7.0",
85
+ "@nxtedition/nxt-undici": "^4.1.3",
86
86
  "content-type": "^1.0.5",
87
87
  "date-fns": "^3.6.0",
88
88
  "fast-querystring": "^1.1.1",
@@ -91,14 +91,14 @@
91
91
  "json5": "^2.2.3",
92
92
  "koa-compose": "^4.1.0",
93
93
  "lodash": "^4.17.21",
94
- "mime": "^4.0.1",
94
+ "mime": "^4.0.4",
95
95
  "moment-timezone": "^0.5.45",
96
96
  "nconf": "^0.12.1",
97
97
  "nested-error-stacks": "^2.1.1",
98
98
  "object-hash": "^3.0.0",
99
99
  "p-queue": "^8.0.1",
100
100
  "pino": "^9.2.0",
101
- "qs": "^6.12.1",
101
+ "qs": "^6.12.3",
102
102
  "request-target": "^1.0.2",
103
103
  "smpte-timecode": "^1.3.6",
104
104
  "split-string": "^6.0.0",
@@ -109,7 +109,7 @@
109
109
  "devDependencies": {
110
110
  "@nxtedition/deepstream.io-client-js": ">=24.2.4",
111
111
  "@types/lodash": "^4.17.6",
112
- "@types/node": "^20.14.9",
112
+ "@types/node": "^20.14.10",
113
113
  "eslint": "^8.0.0",
114
114
  "eslint-config-prettier": "^9.1.0",
115
115
  "eslint-config-standard": "^17.0.0",