@nxtedition/lib 19.0.51 → 19.1.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.
Files changed (2) hide show
  1. package/couch.js +299 -88
  2. package/package.json +1 -1
package/couch.js CHANGED
@@ -1,9 +1,9 @@
1
1
  import assert from 'node:assert'
2
+ import querystring from 'node:querystring'
2
3
  import createError from 'http-errors'
3
4
  import { makeWeakCache } from './weakCache.js'
4
5
  import tp from 'timers/promises'
5
6
  import { defaultDelay as delay } from './http.js'
6
- import querystring from 'querystring'
7
7
  import urljoin from 'url-join'
8
8
  import undici from 'undici'
9
9
  import { AbortError } from './errors.js'
@@ -560,93 +560,7 @@ export function makeCouch(opts) {
560
560
 
561
561
  const { client = getClient(pathname), signal, idempotent = true, ...options } = opts
562
562
 
563
- const params = {}
564
- const headers = ['Accept', 'application/json']
565
-
566
- let method = 'GET'
567
- let body
568
-
569
- if (options.conflicts) {
570
- params.conflicts = true
571
- }
572
-
573
- if (options.update_seq) {
574
- params.update_seq = true
575
- }
576
-
577
- if (options.descending) {
578
- params.descending = true
579
- }
580
-
581
- if (options.include_docs) {
582
- params.include_docs = true
583
- }
584
-
585
- if (options.include_docs) {
586
- params.include_docs = true
587
- }
588
-
589
- if (options.sorted) {
590
- params.sorted = true
591
- }
592
-
593
- if (options.key != null) {
594
- params.key = JSON.stringify(options.key)
595
- }
596
-
597
- if (options.start_key != null) {
598
- options.startkey = options.start_key
599
- }
600
-
601
- if (options.startkey != null) {
602
- params.startkey = JSON.stringify(options.startkey)
603
- }
604
-
605
- if (options.startkey_docid != null) {
606
- params.startkey_docid = JSON.stringify(options.startkey_docid)
607
- }
608
-
609
- if (options.end_key != null) {
610
- options.endkey = options.end_key
611
- }
612
-
613
- if (options.endkey != null) {
614
- params.endkey = JSON.stringify(options.endkey)
615
- }
616
-
617
- if (options.inclusive_end != null) {
618
- params.inclusive_end = !!options.inclusive_end
619
- }
620
-
621
- if (options.limit != null) {
622
- params.limit = options.limit
623
- }
624
-
625
- if (options.skip != null) {
626
- params.skip = options.skip
627
- }
628
-
629
- if (options.stale != null) {
630
- params.stale = options.stale
631
- }
632
-
633
- if (options.reduce != null) {
634
- params.reduce = options.reduce
635
- }
636
-
637
- if (options.group != null) {
638
- params.group = options.group
639
- }
640
-
641
- if (options.group_level != null) {
642
- params.group_level = options.group_level
643
- }
644
-
645
- if (options.keys != null) {
646
- method = 'POST'
647
- body = { keys: options.keys }
648
- headers.push('Content-Type', 'application/json')
649
- }
563
+ const { params, method, headers, body } = _normalizeAllDocsOptions(options)
650
564
 
651
565
  const req = {
652
566
  pathname: pathname || '_all_docs',
@@ -848,3 +762,300 @@ export function makeCouch(opts) {
848
762
  up,
849
763
  })
850
764
  }
765
+
766
+ /* eslint-disable camelcase */
767
+ function _normalizeAllDocsOptions({
768
+ conflicts,
769
+ update_seq,
770
+ descending,
771
+ include_docs,
772
+ sorted,
773
+ key,
774
+ startkey,
775
+ start_key,
776
+ startkey_docid,
777
+ endkey,
778
+ end_key,
779
+ endkey_docid,
780
+ inclusive_end,
781
+ limit,
782
+ skip,
783
+ stale,
784
+ reduce,
785
+ stable,
786
+ update,
787
+ keys,
788
+ group,
789
+ group_level,
790
+ ...rest
791
+ }) {
792
+ if (Object.keys(rest).length > 0) {
793
+ throw new Error('invalid options: ' + JSON.stringify(rest))
794
+ }
795
+ const params = {}
796
+ const headers = {
797
+ Accept: 'application/json',
798
+ }
799
+
800
+ let method = 'GET'
801
+ let body
802
+
803
+ if (conflicts) {
804
+ params.conflicts = true
805
+ }
806
+
807
+ if (update_seq) {
808
+ params.update_seq = true
809
+ }
810
+
811
+ if (descending) {
812
+ params.descending = true
813
+ }
814
+
815
+ if (include_docs) {
816
+ params.include_docs = true
817
+ }
818
+
819
+ if (sorted) {
820
+ params.sorted = true
821
+ }
822
+
823
+ if (key != null) {
824
+ params.key = JSON.stringify(key)
825
+ }
826
+
827
+ if (startkey != null || start_key != null) {
828
+ params.startkey = JSON.stringify(startkey ?? start_key)
829
+ }
830
+
831
+ if (startkey_docid != null) {
832
+ params.startkey_docid = JSON.stringify(startkey_docid)
833
+ }
834
+
835
+ if (endkey != null || end_key != null) {
836
+ params.endkey = JSON.stringify(endkey ?? end_key)
837
+ }
838
+
839
+ if (inclusive_end != null) {
840
+ params.inclusive_end = !!inclusive_end
841
+ }
842
+
843
+ if (limit != null) {
844
+ params.limit = limit
845
+ }
846
+
847
+ if (skip != null) {
848
+ params.skip = skip
849
+ }
850
+
851
+ if (stale != null) {
852
+ params.stale = stale
853
+ }
854
+
855
+ if (reduce != null) {
856
+ params.reduce = reduce
857
+ }
858
+
859
+ if (group != null) {
860
+ params.group = group
861
+ }
862
+
863
+ if (group_level != null) {
864
+ params.group_level = group_level
865
+ }
866
+
867
+ if (update != null) {
868
+ params.update = update
869
+ }
870
+
871
+ if (stable != null) {
872
+ params.stable = stable
873
+ }
874
+
875
+ if (keys != null) {
876
+ method = 'POST'
877
+ body = JSON.stringify({ keys })
878
+ headers['Content-Type'] = 'application/json'
879
+ }
880
+
881
+ return {
882
+ method,
883
+ params,
884
+ headers,
885
+ body,
886
+ }
887
+ }
888
+
889
+ class Handler {
890
+ #state = 0
891
+ #str = ''
892
+ #decoder = new TextDecoder()
893
+ #resolve
894
+ #reject
895
+ #resume
896
+ #abort
897
+ #onAbort
898
+ #signal
899
+ #next
900
+ #statusCode
901
+ #statusText
902
+ #opts
903
+
904
+ constructor({ opts, signal, resolve, reject, next }) {
905
+ this.#next = next
906
+ this.#opts = opts
907
+ this.#resolve = resolve
908
+ this.#reject = reject
909
+ this.#signal = signal
910
+ }
911
+
912
+ onConnect(abort) {
913
+ if (this.#signal?.aborted) {
914
+ abort(this.#signal.reason)
915
+ } else {
916
+ this.#abort = abort
917
+ if (this.#signal) {
918
+ this.#onAbort = () => abort(this.#signal.reason)
919
+ this.#signal.addEventListener('abort', this.#onAbort)
920
+ }
921
+ }
922
+ }
923
+
924
+ onHeaders(statusCode, rawHeaders, resume, statusText) {
925
+ this.#statusCode = statusCode
926
+ this.#statusText = statusText
927
+ this.#resume = resume
928
+
929
+ if (this.#statusCode >= 200 && this.#statusCode < 300) {
930
+ this.#next = null
931
+ }
932
+ }
933
+
934
+ onData(data) {
935
+ if (!this.#next) {
936
+ this.#str += this.#decoder.decode(data, { stream: true })
937
+ } else {
938
+ const lines = this.#decoder.decode(data, { stream: true }).split(/\r?\n+/)
939
+ lines[0] = this.#str + lines[0]
940
+ this.#str = lines.pop() ?? ''
941
+
942
+ const rows = []
943
+ for (const line of lines) {
944
+ if (this.#state === 0) {
945
+ if (line.endsWith('[')) {
946
+ this.#state = 1
947
+ } else {
948
+ throw new Error('unexpected data')
949
+ }
950
+ } else if (this.#state === 1) {
951
+ if (line.startsWith(']')) {
952
+ this.#state = 2
953
+ } else {
954
+ rows.push(JSON.parse(line.slice(0, line.lastIndexOf('}') + 1)))
955
+ }
956
+ }
957
+ }
958
+
959
+ if (rows.length === 0) {
960
+ return true
961
+ }
962
+
963
+ const thenable = this.#next(rows)
964
+
965
+ if (!thenable) {
966
+ return true
967
+ }
968
+
969
+ thenable.then(this.#resume, this.#abort)
970
+
971
+ return false
972
+ }
973
+ }
974
+
975
+ onComplete() {
976
+ assert(!this.#next || this.#state === 2)
977
+
978
+ if (!this.#next) {
979
+ this.#str += this.#decoder.decode(undefined, { stream: false })
980
+
981
+ if (this.#statusCode >= 200 && this.#statusCode < 300) {
982
+ this.onFinally(null, this.#next ? null : JSON.parse(this.#str))
983
+ } else {
984
+ let body
985
+ let reason
986
+ let error
987
+ try {
988
+ body = JSON.parse(this.#str)
989
+ reason = body.reason
990
+ error = body.error
991
+ } catch {
992
+ // Do nothing...
993
+ }
994
+
995
+ this.onFinally(
996
+ Object.assign(new Error(this.#statusText ?? reason), {
997
+ reason,
998
+ error,
999
+ data: {
1000
+ req: this.#opts,
1001
+ res: {
1002
+ body,
1003
+ statusCode: this.#statusCode,
1004
+ },
1005
+ },
1006
+ }),
1007
+ )
1008
+ }
1009
+ } else {
1010
+ this.onFinally(null)
1011
+ }
1012
+ }
1013
+
1014
+ onError(err) {
1015
+ this.onFinally(err)
1016
+ }
1017
+
1018
+ onFinally(err, val) {
1019
+ if (this.#signal) {
1020
+ this.#signal.removeEventListener('abort', this.#onAbort)
1021
+ }
1022
+
1023
+ if (err) {
1024
+ this.#reject(err)
1025
+ } else {
1026
+ this.#resolve(val)
1027
+ }
1028
+ }
1029
+ }
1030
+
1031
+ export async function request(
1032
+ url,
1033
+ {
1034
+ body,
1035
+ method = body ? 'POST' : 'GET',
1036
+ query,
1037
+ headers,
1038
+ dispatcher = undici.getGlobalDispatcher(),
1039
+ signal,
1040
+ },
1041
+ next,
1042
+ ) {
1043
+ url = new URL(url)
1044
+ if (url.search) {
1045
+ throw new Error('invalid url: ' + url.href)
1046
+ }
1047
+ const opts = {
1048
+ origin: url.origin,
1049
+ path: url.pathname + '?' + querystring.stringify(query),
1050
+ method,
1051
+ headers: {
1052
+ 'content-type': body != null && typeof body === 'object' ? 'application/json' : 'plain/text',
1053
+ accept: 'application/json',
1054
+ ...headers,
1055
+ },
1056
+ body: body != null && typeof body === 'object' ? JSON.stringify(body) : body,
1057
+ }
1058
+ return new Promise((resolve, reject) => {
1059
+ dispatcher.dispatch(opts, new Handler({ opts, signal, resolve, reject, next }))
1060
+ })
1061
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/lib",
3
- "version": "19.0.51",
3
+ "version": "19.1.0",
4
4
  "license": "MIT",
5
5
  "author": "Robert Nagy <robert.nagy@boffins.se>",
6
6
  "type": "module",