@nxtedition/lib 18.0.10 → 19.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/couch.js +72 -114
- package/package.json +1 -1
package/couch.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import assert from 'node:assert'
|
|
1
2
|
import createError from 'http-errors'
|
|
2
3
|
import { makeWeakCache } from './weakCache.js'
|
|
3
4
|
import tp from 'timers/promises'
|
|
@@ -225,16 +226,21 @@ export function makeCouch(opts) {
|
|
|
225
226
|
}
|
|
226
227
|
}
|
|
227
228
|
|
|
228
|
-
async function*
|
|
229
|
+
async function* parse(live) {
|
|
230
|
+
let remaining = Number(options.limit) || Infinity
|
|
231
|
+
|
|
232
|
+
const params2 = {
|
|
233
|
+
...params,
|
|
234
|
+
...options.query,
|
|
235
|
+
feed: live ? 'continuous' : 'normal',
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
if (Number.isFinite(remaining)) {
|
|
239
|
+
params.limit = remaining
|
|
240
|
+
}
|
|
241
|
+
|
|
229
242
|
const req = {
|
|
230
|
-
path:
|
|
231
|
-
dbPathname +
|
|
232
|
-
'/_changes' +
|
|
233
|
-
`?${new URLSearchParams({
|
|
234
|
-
...params,
|
|
235
|
-
...options.query,
|
|
236
|
-
feed: 'continuous',
|
|
237
|
-
})}`,
|
|
243
|
+
path: `${dbPathname}/_changes?${new URLSearchParams(params2)}`,
|
|
238
244
|
idempotent: false,
|
|
239
245
|
blocking: true,
|
|
240
246
|
method,
|
|
@@ -245,10 +251,14 @@ export function makeCouch(opts) {
|
|
|
245
251
|
'request-id': genReqId(),
|
|
246
252
|
...(body ? { 'content-type': 'application/json' } : {}),
|
|
247
253
|
},
|
|
254
|
+
throwOnError: true,
|
|
248
255
|
highWaterMark: 256 * 1024, // TODO (fix): Needs support in undici...
|
|
249
256
|
bodyTimeout: 2 * (params.heartbeat || 60e3),
|
|
250
257
|
}
|
|
251
258
|
|
|
259
|
+
const HEAD = '{"results":['
|
|
260
|
+
const TAIL = '],'
|
|
261
|
+
|
|
252
262
|
try {
|
|
253
263
|
const res = await client.request(req)
|
|
254
264
|
|
|
@@ -262,29 +272,68 @@ export function makeCouch(opts) {
|
|
|
262
272
|
|
|
263
273
|
retryCount = 0
|
|
264
274
|
|
|
275
|
+
const decoder = new TextDecoder()
|
|
276
|
+
|
|
265
277
|
let str = ''
|
|
278
|
+
let state = 0
|
|
266
279
|
for await (const chunk of res.body) {
|
|
267
|
-
|
|
280
|
+
str += decoder.decode(chunk, { stream: true })
|
|
281
|
+
|
|
282
|
+
const lines = str.split('\n')
|
|
268
283
|
str = lines.pop() ?? ''
|
|
269
284
|
|
|
270
|
-
const
|
|
285
|
+
const changes = []
|
|
271
286
|
for (const line of lines) {
|
|
272
|
-
if (line) {
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
287
|
+
if (line === '') {
|
|
288
|
+
continue
|
|
289
|
+
}
|
|
290
|
+
if (live) {
|
|
291
|
+
const data = JSON.parse(line)
|
|
292
|
+
if (data.last_seq) {
|
|
293
|
+
params.since = data.last_seq
|
|
294
|
+
assert(params.since, 'invalid last_seq: ' + params.since)
|
|
295
|
+
} else {
|
|
296
|
+
params.since = data.seq || params.since
|
|
297
|
+
changes.push(data)
|
|
276
298
|
}
|
|
277
|
-
|
|
278
|
-
|
|
299
|
+
} else {
|
|
300
|
+
// NOTE: This makes some assumptions about the format of the JSON.
|
|
301
|
+
if (state === 0) {
|
|
302
|
+
if (line === HEAD) {
|
|
303
|
+
state = 1
|
|
304
|
+
} else {
|
|
305
|
+
assert(line.length < HEAD.length, 'invalid line: ' + line)
|
|
306
|
+
}
|
|
307
|
+
} else if (state === 1) {
|
|
308
|
+
if (line === TAIL) {
|
|
309
|
+
state = 2
|
|
310
|
+
} else {
|
|
311
|
+
const idx = line.lastIndexOf('}') + 1
|
|
312
|
+
assert(idx > 0, 'invalid line; ' + line)
|
|
313
|
+
const data = JSON.parse(line.slice(0, idx))
|
|
314
|
+
params.since = data.seq || params.since
|
|
315
|
+
changes.push(data)
|
|
316
|
+
}
|
|
317
|
+
} else if (state === 2) {
|
|
318
|
+
state = 3
|
|
319
|
+
params.since = JSON.parse('{' + line).last_seq
|
|
320
|
+
assert(params.since, 'invalid last_seq: ' + params.since)
|
|
279
321
|
} else {
|
|
280
|
-
|
|
322
|
+
assert(false, 'invalid state: ' + state)
|
|
281
323
|
}
|
|
282
324
|
}
|
|
283
325
|
}
|
|
284
326
|
|
|
285
|
-
if (
|
|
286
|
-
|
|
327
|
+
if (changes.length > 0) {
|
|
328
|
+
if (batched) {
|
|
329
|
+
yield changes
|
|
330
|
+
} else {
|
|
331
|
+
yield* changes
|
|
332
|
+
}
|
|
287
333
|
}
|
|
334
|
+
|
|
335
|
+
remaining -= changes.length
|
|
336
|
+
assert(remaining >= 0, 'invalid remaining: ' + remaining)
|
|
288
337
|
}
|
|
289
338
|
} catch (err) {
|
|
290
339
|
Object.assign(err, { data: req })
|
|
@@ -292,108 +341,17 @@ export function makeCouch(opts) {
|
|
|
292
341
|
}
|
|
293
342
|
}
|
|
294
343
|
|
|
295
|
-
async function* normal() {
|
|
296
|
-
const batchSize =
|
|
297
|
-
options.batch_size ?? options.batchSize ?? (params.include_docs ? 512 : 4096)
|
|
298
|
-
let remaining = parseInt(options.limit) || Infinity
|
|
299
|
-
|
|
300
|
-
const next = async () => {
|
|
301
|
-
const req = {
|
|
302
|
-
path:
|
|
303
|
-
dbPathname +
|
|
304
|
-
'/_changes' +
|
|
305
|
-
`?${new URLSearchParams({
|
|
306
|
-
...params,
|
|
307
|
-
...options.query,
|
|
308
|
-
limit: Math.min(remaining, batchSize),
|
|
309
|
-
feed: live ? 'longpoll' : 'normal',
|
|
310
|
-
})}`,
|
|
311
|
-
idempotent: true,
|
|
312
|
-
blocking: live,
|
|
313
|
-
method,
|
|
314
|
-
maxRedirects: 4,
|
|
315
|
-
body: JSON.stringify(body),
|
|
316
|
-
signal: ac.signal,
|
|
317
|
-
headers: {
|
|
318
|
-
'user-agent': userAgent,
|
|
319
|
-
'request-id': genReqId(),
|
|
320
|
-
...(body ? { 'content-type': 'application/json' } : {}),
|
|
321
|
-
},
|
|
322
|
-
}
|
|
323
|
-
|
|
324
|
-
try {
|
|
325
|
-
const res = await client.request(req)
|
|
326
|
-
|
|
327
|
-
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
328
|
-
throw makeError(req, {
|
|
329
|
-
status: res.statusCode,
|
|
330
|
-
headers: res.headers,
|
|
331
|
-
data: await res.body.text(),
|
|
332
|
-
})
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
return await res.body.json()
|
|
336
|
-
} catch (err) {
|
|
337
|
-
Object.assign(err, { data: req })
|
|
338
|
-
throw err
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
let promise
|
|
343
|
-
while (remaining) {
|
|
344
|
-
const { last_seq: seq, results, err } = await (promise ?? next())
|
|
345
|
-
promise = null
|
|
346
|
-
|
|
347
|
-
if (err) {
|
|
348
|
-
throw err
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
retryCount = 0
|
|
352
|
-
|
|
353
|
-
if (seq) {
|
|
354
|
-
params.since = seq
|
|
355
|
-
if (results.length > 0 && !results.at(-1)?.seq) {
|
|
356
|
-
results.at(-1).seq = seq
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
remaining -= results.length
|
|
361
|
-
|
|
362
|
-
if (!live && results.length === 0) {
|
|
363
|
-
return
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
promise = next().catch((err) => ({ err }))
|
|
367
|
-
|
|
368
|
-
if (batched) {
|
|
369
|
-
yield results
|
|
370
|
-
} else {
|
|
371
|
-
yield* results
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
344
|
try {
|
|
377
345
|
while (true) {
|
|
378
346
|
try {
|
|
379
|
-
|
|
380
|
-
yield* continuous()
|
|
381
|
-
} else {
|
|
382
|
-
yield* normal()
|
|
383
|
-
}
|
|
347
|
+
yield* parse(live)
|
|
384
348
|
return
|
|
385
349
|
} catch (err) {
|
|
386
|
-
err.
|
|
387
|
-
if (err.name === 'AbortError' || client.destroyed) {
|
|
350
|
+
if (err.name === 'AbortError') {
|
|
388
351
|
throw err
|
|
389
352
|
} else if (typeof retry === 'function') {
|
|
390
353
|
const retryState = { since: params.since }
|
|
391
|
-
Object.assign(
|
|
392
|
-
retryState,
|
|
393
|
-
await retry(err, retryCount++, retryState, { signal }, () =>
|
|
394
|
-
delay(err, retryCount, { signal }),
|
|
395
|
-
),
|
|
396
|
-
)
|
|
354
|
+
Object.assign(retryState, await retry(err, retryCount++, retryState, { signal }))
|
|
397
355
|
params.since = retryState.since ?? 0
|
|
398
356
|
} else {
|
|
399
357
|
await delay(err, retryCount, { signal })
|