@nxtedition/lib 17.2.23 → 18.0.1
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 +63 -103
- package/package.json +1 -1
package/couch.js
CHANGED
|
@@ -5,6 +5,7 @@ import { defaultDelay as delay } from './http.js'
|
|
|
5
5
|
import querystring from 'querystring'
|
|
6
6
|
import urljoin from 'url-join'
|
|
7
7
|
import undici from 'undici'
|
|
8
|
+
import assert from 'node:assert'
|
|
8
9
|
|
|
9
10
|
// https://github.com/fastify/fastify/blob/main/lib/reqIdGenFactory.js
|
|
10
11
|
// 2,147,483,647 (2^31 − 1) stands for max SMI value (an internal optimization of V8).
|
|
@@ -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,
|
|
@@ -250,34 +256,66 @@ export function makeCouch(opts) {
|
|
|
250
256
|
bodyTimeout: 2 * (params.heartbeat || 60e3),
|
|
251
257
|
}
|
|
252
258
|
|
|
259
|
+
const HEAD = '{"results":['
|
|
260
|
+
const TAIL = '],'
|
|
261
|
+
|
|
253
262
|
try {
|
|
254
263
|
const res = await client.request(req)
|
|
255
264
|
|
|
256
265
|
retryCount = 0
|
|
257
266
|
|
|
258
267
|
let str = ''
|
|
268
|
+
let state = 0
|
|
259
269
|
for await (const chunk of res.body) {
|
|
260
270
|
const lines = (str + chunk).split('\n')
|
|
261
271
|
str = lines.pop() ?? ''
|
|
262
272
|
|
|
263
|
-
const
|
|
273
|
+
const changes = []
|
|
264
274
|
for (const line of lines) {
|
|
265
|
-
if (line) {
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
275
|
+
if (line === '') {
|
|
276
|
+
continue
|
|
277
|
+
}
|
|
278
|
+
if (live) {
|
|
279
|
+
const data = JSON.parse(line)
|
|
280
|
+
if (data.last_seq) {
|
|
281
|
+
params.since = data.last_seq
|
|
282
|
+
assert(params.since, 'invalid last_seq: ' + params.since)
|
|
283
|
+
} else {
|
|
284
|
+
params.since = data.seq || params.since
|
|
285
|
+
changes.push(data)
|
|
269
286
|
}
|
|
270
|
-
|
|
271
|
-
|
|
287
|
+
} else {
|
|
288
|
+
// NOTE: This makes some assumptions about the format of the JSON.
|
|
289
|
+
if (state === 0) {
|
|
290
|
+
if (line === HEAD) {
|
|
291
|
+
state = 1
|
|
292
|
+
} else {
|
|
293
|
+
assert(line.length < HEAD.length, 'invalid line: ' + line)
|
|
294
|
+
}
|
|
295
|
+
} else if (state === 1) {
|
|
296
|
+
if (line === TAIL) {
|
|
297
|
+
state = 2
|
|
298
|
+
} else {
|
|
299
|
+
const idx = line.lastIndexOf('}') + 1
|
|
300
|
+
assert(idx > 0, 'invalid line; ' + line)
|
|
301
|
+
const data = JSON.parse(line.slice(0, idx))
|
|
302
|
+
params.since = data.seq || params.since
|
|
303
|
+
changes.push(data)
|
|
304
|
+
}
|
|
305
|
+
} else if (state === 2) {
|
|
306
|
+
state = 3
|
|
307
|
+
params.since = JSON.parse('{' + line).last_seq
|
|
308
|
+
assert(params.since, 'invalid last_seq: ' + params.since)
|
|
272
309
|
} else {
|
|
273
|
-
|
|
310
|
+
assert(false, 'invalid state: ' + state)
|
|
274
311
|
}
|
|
275
312
|
}
|
|
276
313
|
}
|
|
277
314
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
315
|
+
yield changes
|
|
316
|
+
|
|
317
|
+
remaining -= changes.length
|
|
318
|
+
assert(remaining >= 0, 'invalid remaining: ' + remaining)
|
|
281
319
|
}
|
|
282
320
|
} catch (err) {
|
|
283
321
|
Object.assign(err, { data: req })
|
|
@@ -285,93 +323,15 @@ export function makeCouch(opts) {
|
|
|
285
323
|
}
|
|
286
324
|
}
|
|
287
325
|
|
|
288
|
-
async function* normal() {
|
|
289
|
-
const batchSize =
|
|
290
|
-
options.batch_size ?? options.batchSize ?? (params.include_docs ? 512 : 4096)
|
|
291
|
-
let remaining = parseInt(options.limit) || Infinity
|
|
292
|
-
|
|
293
|
-
const next = async () => {
|
|
294
|
-
const req = {
|
|
295
|
-
path:
|
|
296
|
-
dbPathname +
|
|
297
|
-
'/_changes' +
|
|
298
|
-
`?${new URLSearchParams({
|
|
299
|
-
...params,
|
|
300
|
-
...options.query,
|
|
301
|
-
limit: Math.min(remaining, batchSize),
|
|
302
|
-
feed: live ? 'longpoll' : 'normal',
|
|
303
|
-
})}`,
|
|
304
|
-
idempotent: true,
|
|
305
|
-
blocking: live,
|
|
306
|
-
method,
|
|
307
|
-
body: JSON.stringify(body),
|
|
308
|
-
signal: ac.signal,
|
|
309
|
-
headers: {
|
|
310
|
-
'user-agent': userAgent,
|
|
311
|
-
'request-id': genReqId(),
|
|
312
|
-
...(body ? { 'content-type': 'application/json' } : {}),
|
|
313
|
-
},
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
try {
|
|
317
|
-
const res = await client.request(req)
|
|
318
|
-
|
|
319
|
-
if (res.statusCode < 200 || res.statusCode >= 300) {
|
|
320
|
-
throw makeError(req, {
|
|
321
|
-
status: res.statusCode,
|
|
322
|
-
headers: res.headers,
|
|
323
|
-
data: await res.body.text(),
|
|
324
|
-
})
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
return await res.body.json()
|
|
328
|
-
} catch (err) {
|
|
329
|
-
Object.assign(err, { data: req })
|
|
330
|
-
return { err }
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
let promise
|
|
335
|
-
while (remaining) {
|
|
336
|
-
const { last_seq: seq, results, err } = await (promise ?? next())
|
|
337
|
-
promise = null
|
|
338
|
-
|
|
339
|
-
if (err) {
|
|
340
|
-
throw err
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
retryCount = 0
|
|
344
|
-
|
|
345
|
-
if (seq) {
|
|
346
|
-
params.since = seq
|
|
347
|
-
if (results.length > 0 && !results.at(-1)?.seq) {
|
|
348
|
-
results.at(-1).seq = seq
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
remaining -= results.length
|
|
353
|
-
|
|
354
|
-
if (!live && results.length === 0) {
|
|
355
|
-
return
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
promise = next()
|
|
359
|
-
|
|
360
|
-
if (batched) {
|
|
361
|
-
yield results
|
|
362
|
-
} else {
|
|
363
|
-
yield* results
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
|
|
368
326
|
try {
|
|
369
327
|
while (true) {
|
|
370
328
|
try {
|
|
371
|
-
if (
|
|
372
|
-
yield*
|
|
329
|
+
if (batched) {
|
|
330
|
+
yield* parse(live)
|
|
373
331
|
} else {
|
|
374
|
-
|
|
332
|
+
for await (const changes of parse(live)) {
|
|
333
|
+
yield* changes
|
|
334
|
+
}
|
|
375
335
|
}
|
|
376
336
|
return
|
|
377
337
|
} catch (err) {
|