braid-http 1.3.44 → 1.3.46

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.
@@ -1,4 +1,3 @@
1
- // var peer = Math.random().toString(36).substr(2)
2
1
 
3
2
  // ***************************
4
3
  // http
@@ -163,7 +162,10 @@ async function braid_fetch (url, params = {}) {
163
162
  params.headers.set('peer', params.peer)
164
163
 
165
164
  if (params.heartbeats)
166
- params.headers.set('heartbeats', typeof params.heartbeats === 'number' ? `${params.heartbeats}s` : params.heartbeats)
165
+ params.headers.set('heartbeats',
166
+ typeof params.heartbeats === 'number'
167
+ ? `${params.heartbeats}s`
168
+ : params.heartbeats)
167
169
 
168
170
  // Prevent browsers from going to disk cache
169
171
  params.cache = 'no-cache'
@@ -262,7 +264,7 @@ async function braid_fetch (url, params = {}) {
262
264
  underlying_aborter?.abort()
263
265
 
264
266
  // see if we should retry..
265
- var retry = params.retry && // only try to reconnect if the user has chosen to
267
+ var retry = params.retry && // only try to reconnect if the user has chosen to
266
268
  e.name !== "AbortError" && // don't retry if the user has chosen to abort
267
269
  !e.startsWith?.('Parse error in headers') && // in this case, the server is spewing garbage, so reconnecting might be bad
268
270
  !e.message?.startsWith?.('Could not establish multiplexed request') && // the server has told us no, or is using a different version of multiplexing
@@ -313,10 +315,9 @@ async function braid_fetch (url, params = {}) {
313
315
  (params.headers.has('subscribe') &&
314
316
  braid_fetch.subscription_counts?.[origin] >
315
317
  (!mux_params ? 1 : (mux_params.after ?? 0))))) {
316
- res = await multiplex_fetch(url, params, mux_params?.via === 'POST')
317
- } else {
318
+ res = await multiplex_fetch(url, params, mux_params)
319
+ } else
318
320
  res = await normal_fetch(url, params)
319
- }
320
321
 
321
322
  // And customize the response with a couple methods for getting
322
323
  // the braid subscription data:
@@ -338,7 +339,7 @@ async function braid_fetch (url, params = {}) {
338
339
  clearTimeout(timeout)
339
340
  let wait_seconds = 1.2 * heartbeats + 3
340
341
  timeout = setTimeout(() => {
341
- on_error(new Error(`heartbeat not seen in ${wait_seconds.toFixed(2)}s`))
342
+ on_error(new Error(`heartbeat seen in ${wait_seconds.toFixed(2)}s`))
342
343
  }, wait_seconds * 1000)
343
344
  }
344
345
  on_heartbeat()
@@ -361,7 +362,8 @@ async function braid_fetch (url, params = {}) {
361
362
  async (result, err) => {
362
363
  if (!err) {
363
364
  // check whether we aborted
364
- if (original_signal?.aborted) throw create_abort_error('already aborted')
365
+ if (original_signal?.aborted)
366
+ throw create_abort_error('already aborted')
365
367
 
366
368
  // Yay! We got a new version! Tell the callback!
367
369
  cb_running = true
@@ -540,7 +542,8 @@ var subscription_parser = (cb) => ({
540
542
 
541
543
  Object.defineProperty(update, 'body_text', {
542
544
  get: function () {
543
- if (this.body != null) return new TextDecoder('utf-8').decode(this.body.buffer)
545
+ if (this.body != null)
546
+ return new TextDecoder('utf-8').decode(this.body.buffer)
544
547
  }
545
548
  })
546
549
 
@@ -634,7 +637,9 @@ function parse_headers (input) {
634
637
 
635
638
  // Extract the header string
636
639
  var headers_source = input.slice(start, end)
637
- headers_source = Array.isArray(headers_source) ? headers_source.map(x => String.fromCharCode(x)).join('') : new TextDecoder().decode(headers_source)
640
+ headers_source = Array.isArray(headers_source)
641
+ ? headers_source.map(x => String.fromCharCode(x)).join('')
642
+ : new TextDecoder().decode(headers_source)
638
643
 
639
644
  // Convert "HTTP 200 OK" to a :status: 200 header
640
645
  headers_source = headers_source.replace(/^HTTP\/?\d*\.?\d* (\d\d\d).*\r?\n/,
@@ -827,7 +832,7 @@ function parse_body (state) {
827
832
 
828
833
  // multiplex_fetch provides a fetch-like experience for HTTP requests
829
834
  // where the result is actually being sent over a separate multiplexed connection.
830
- async function multiplex_fetch(url, params, skip_multiplex_method) {
835
+ async function multiplex_fetch(url, params, mux_params) {
831
836
  var multiplex_version = '1.0'
832
837
 
833
838
  var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
@@ -837,215 +842,238 @@ async function multiplex_fetch(url, params, skip_multiplex_method) {
837
842
  var mux_key = params.headers.get('multiplex-through')?.split('/')[3] ?? origin
838
843
 
839
844
  // create a new multiplexer if it doesn't exist for this origin
840
- if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
841
- if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (async () => {
842
- // make up a new multiplexer id (unless it is being overriden)
843
- var multiplexer = params.headers.get('multiplex-through')?.split('/')[3] ?? Math.random().toString(36).slice(2)
845
+ if (!multiplex_fetch.multiplexers) multiplex_fetch.multiplexers = {}
846
+ if (!multiplex_fetch.multiplexers[mux_key]) multiplex_fetch.multiplexers[mux_key] = (
847
+ async () => {
848
+ // make up a new multiplexer id (unless it is being overriden)
849
+ var multiplexer = params.headers.get('multiplex-through')?.split('/')[3]
850
+ ?? random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
844
851
 
845
- var requests = new Map()
846
- var mux_error = null
847
-
848
- var mux_promise = (async () => {
849
- // attempt to establish a multiplexed connection
850
- try {
851
- if (skip_multiplex_method) throw 'skip multiplex method'
852
- var r = await braid_fetch(`${origin}/${multiplexer}`, {method: 'MULTIPLEX', headers: {'Multiplex-Version': multiplex_version}, retry: true})
853
- if (!r.ok || r.headers.get('Multiplex-Version') !== multiplex_version) throw 'bad'
854
- } catch (e) {
855
- // some servers don't like custom methods,
856
- // so let's try with a custom header
857
- try {
858
- r = await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}`, {method: 'POST', headers: {'Multiplex-Version': multiplex_version}, retry: true})
852
+ var requests = new Map()
853
+ var mux_error = null
859
854
 
860
- if (!r.ok) throw new Error('status not ok: ' + r.status)
861
- if (r.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected ' + multiplex_version)
862
- } catch (e) {
863
- // fallback to normal fetch if multiplexed connection fails
864
- console.error(`Could not establish multiplexer.\nGot error: ${e}.\nFalling back to normal connection.`)
865
- return false
866
- }
867
- }
868
-
869
- // parse the multiplexed stream,
870
- // and send messages to the appropriate requests
871
- var try_deleting = new Set()
872
- parse_multiplex_stream(r.body.getReader(), async (request, bytes) => {
873
- if (requests.has(request)) {
874
- requests.get(request)(bytes)
875
- } else if (!try_deleting.has(request)) {
876
- try_deleting.add(request)
877
- try {
878
- await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}/${request}`, {
879
- method: 'DELETE',
880
- headers: { 'Multiplex-Version': multiplex_version }, retry: true
881
- })
882
- } finally { try_deleting.delete(request) }
883
- }
884
- }, e => {
855
+ function cleanup(e) {
885
856
  // the multiplexer stream has died.. let everyone know..
886
857
  mux_error = e
887
- for (var f of requests.values()) f()
888
858
  delete multiplex_fetch.multiplexers[mux_key]
889
- })
890
- })()
891
-
892
- // return a "fetch" for this multiplexer
893
- return async (url, params) => {
894
-
895
- // if we already know the multiplexer is not working,
896
- // then fallback to normal fetch
897
- // (unless the user is specifically asking for multiplexing)
898
- if ((await promise_done(mux_promise)) && (await mux_promise) === false && !params.headers.get('multiplex-through'))
899
- return await normal_fetch(url, params)
900
-
901
- // make up a new request id (unless it is being overriden)
902
- var request = params.headers.get('multiplex-through')?.split('/')[4] ?? Math.random().toString(36).slice(2)
903
-
904
- // add the Multiplex-Through header without affecting the underlying params
905
- var mux_headers = new Headers(params.headers)
906
- mux_headers.set('Multiplex-Through', `/.well-known/multiplexer/${multiplexer}/${request}`)
907
- mux_headers.set('Multiplex-Version', multiplex_version)
908
- params = {...params, headers: mux_headers}
909
-
910
- // setup a way to receive incoming data from the multiplexer
911
- var buffers = []
912
- var bytes_available = () => {}
913
- var request_error = null
914
-
915
- // this utility calls the callback whenever new data is available to process
916
- async function process_buffers(cb) {
917
- while (true) {
918
- // wait for data if none is available
919
- if (!mux_error && !request_error && !buffers.length)
920
- await new Promise(done => bytes_available = done)
921
- if (mux_error || request_error) throw (mux_error || request_error)
922
-
923
- // process the data
924
- let ret = cb()
925
- if (ret) return ret
926
- }
859
+ for (var f of requests.values()) f()
927
860
  }
928
861
 
929
- // tell the multiplexer to send bytes for this request to us
930
- requests.set(request, bytes => {
931
- if (!bytes) buffers.push(bytes)
932
- else if (!mux_error) buffers.push(bytes)
933
- bytes_available()
934
- })
935
-
936
- // prepare a function that we'll call to cleanly tear things down
937
- var unset = async e => {
938
- unset = () => {}
939
- requests.delete(request)
940
- request_error = e
941
- bytes_available()
862
+ var mux_promise = (async () => {
863
+ // attempt to establish a multiplexed connection
942
864
  try {
943
- var r = await braid_fetch(`${origin}${params.headers.get('multiplex-through')}`, {
944
- method: 'DELETE',
945
- headers: { 'Multiplex-Version': multiplex_version }, retry: true
865
+ if (mux_params?.via === 'POST') throw 'skip multiplex method'
866
+ var r = await braid_fetch(`${origin}/${multiplexer}`, {
867
+ method: 'MULTIPLEX',
868
+ headers: {'Multiplex-Version': multiplex_version},
869
+ retry: true
946
870
  })
947
-
948
- if (!r.ok) throw new Error('status not ok: ' + r.status)
949
- if (r.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('wrong multiplex version: ' + r.headers.get('Multiplex-Version') + ', expected ' + multiplex_version)
871
+ if (!r.ok || r.headers.get('Multiplex-Version') !== multiplex_version)
872
+ throw 'bad'
950
873
  } catch (e) {
951
- e = new Error(`Could not cancel multiplexed request: ${e}`)
952
- console.error('' + e)
953
- throw e
874
+ // some servers don't like custom methods,
875
+ // so let's try with a custom header
876
+ try {
877
+ r = await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}`,
878
+ {method: 'POST',
879
+ headers: {'Multiplex-Version': multiplex_version},
880
+ retry: true})
881
+
882
+ if (!r.ok) throw new Error('status not ok: ' + r.status)
883
+ if (r.headers.get('Multiplex-Version') !== multiplex_version)
884
+ throw new Error('wrong multiplex version: '
885
+ + r.headers.get('Multiplex-Version')
886
+ + ', expected ' + multiplex_version)
887
+ } catch (e) {
888
+ // fallback to normal fetch if multiplexed connection fails
889
+ console.error(`Could not establish multiplexer.\n`
890
+ + `Got error: ${e}.\nFalling back to normal connection.`)
891
+ return false
892
+ }
954
893
  }
955
- }
956
894
 
957
- // do the underlying fetch
958
- try {
959
- var mux_was_done = await promise_done(mux_promise)
960
-
961
- var res = await normal_fetch(url, params)
962
-
963
- if (res.status === 424 && !mux_was_done) {
964
- // this error will trigger a retry if the user is using that option
965
- throw new Error('multiplexer not yet connected')
895
+ // parse the multiplexed stream,
896
+ // and send messages to the appropriate requests
897
+ var try_deleting = new Set()
898
+ parse_multiplex_stream(r.body.getReader(), async (request, bytes) => {
899
+ if (requests.has(request)) {
900
+ requests.get(request)(bytes)
901
+ } else if (!try_deleting.has(request)) {
902
+ try_deleting.add(request)
903
+ try {
904
+ await braid_fetch(`${origin}/.well-known/multiplexer/${multiplexer}/${request}`, {
905
+ method: 'DELETE',
906
+ headers: { 'Multiplex-Version': multiplex_version },
907
+ retry: true
908
+ })
909
+ } finally { try_deleting.delete(request) }
910
+ }
911
+ }, cleanup)
912
+ })()
913
+
914
+ // return a "fetch" for this multiplexer
915
+ return async (url, params) => {
916
+
917
+ // make up a new request id (unless it is being overriden)
918
+ var request = params.headers.get('multiplex-through')?.split('/')[4]
919
+ ?? random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
920
+
921
+ // add the Multiplex-Through header without affecting the underlying params
922
+ var mux_headers = new Headers(params.headers)
923
+ mux_headers.set('Multiplex-Through', `/.well-known/multiplexer/${multiplexer}/${request}`)
924
+ mux_headers.set('Multiplex-Version', multiplex_version)
925
+ params = {...params, headers: mux_headers}
926
+
927
+ // setup a way to receive incoming data from the multiplexer
928
+ var buffers = []
929
+ var bytes_available = () => {}
930
+ var request_error = null
931
+
932
+ // this utility calls the callback whenever new data is available to process
933
+ async function process_buffers(cb) {
934
+ while (true) {
935
+ // wait for data if none is available
936
+ if (!mux_error && !request_error && !buffers.length)
937
+ await new Promise(done => bytes_available = done)
938
+ if (mux_error || request_error) throw (mux_error || request_error)
939
+
940
+ // process the data
941
+ let ret = cb()
942
+ if (ret) return ret
943
+ }
966
944
  }
967
945
 
968
- // if the response says it's ok,
969
- // but it's is not a multiplexed response,
970
- // fall back to as if it was a normal fetch
971
- if (res.ok && res.status !== 293) return res
972
-
973
- if (res.status !== 293) throw new Error('Could not establish multiplexed request ' + params.headers.get('multiplex-through') + ', got status: ' + res.status)
974
-
975
- if (res.headers.get('Multiplex-Version') !== multiplex_version) throw new Error('Could not establish multiplexed request ' + params.headers.get('multiplex-through') + ', got unknown version: ' + res.headers.get('Multiplex-Version'))
976
-
977
- // we want to present the illusion that the connection is still open,
978
- // and therefor closable with "abort",
979
- // so we handle the abort ourselves to close the multiplexed request
980
- params.signal?.addEventListener('abort', () =>
981
- unset(create_abort_error('request aborted')))
982
-
983
- // first, we need to listen for the headers..
984
- var headers_buffer = new Uint8Array()
985
- var parsed_headers = await process_buffers(() => {
986
- // check if the request has been closed
987
- var request_ended = !buffers[buffers.length - 1]
988
- if (request_ended) buffers.pop()
989
-
990
- // aggregate all the new buffers into our big headers_buffer
991
- headers_buffer = concat_buffers([headers_buffer, ...buffers])
992
- buffers = []
993
-
994
- // and if the request had ended, put that information back
995
- if (request_ended) buffers.push(null)
996
-
997
- // try parsing what we got so far as headers..
998
- var x = parse_headers(headers_buffer)
999
-
1000
- // how did it go?
1001
- if (x.result === 'error') {
1002
- // if we got an error, give up
1003
- console.log(`headers_buffer: ` + new TextDecoder().decode(headers_buffer))
1004
- throw new Error('error parsing headers')
1005
- } else if (x.result === 'waiting') {
1006
- if (request_ended) throw new Error('Multiplexed request ended before headers received.')
1007
- } else return x
946
+ // tell the multiplexer to send bytes for this request to us
947
+ requests.set(request, bytes => {
948
+ if (!bytes) buffers.push(bytes)
949
+ else if (!mux_error) buffers.push(bytes)
950
+ bytes_available()
1008
951
  })
1009
952
 
1010
- // put the bytes left over from the header back
1011
- if (parsed_headers.input.length) buffers.unshift(parsed_headers.input)
953
+ // prepare a function that we'll call to cleanly tear things down
954
+ var unset = async e => {
955
+ unset = () => {}
956
+ requests.delete(request)
957
+ request_error = e
958
+ bytes_available()
959
+ try {
960
+ var r = await braid_fetch(`${origin}${params.headers.get('multiplex-through')}`, {
961
+ method: 'DELETE',
962
+ headers: { 'Multiplex-Version': multiplex_version }, retry: true
963
+ })
964
+
965
+ if (!r.ok) throw new Error('status not ok: ' + r.status)
966
+ if (r.headers.get('Multiplex-Version') !== multiplex_version)
967
+ throw new Error('wrong multiplex version: '
968
+ + r.headers.get('Multiplex-Version')
969
+ + ', expected ' + multiplex_version)
970
+ } catch (e) {
971
+ e = new Error(`Could not cancel multiplexed request: ${e}`)
972
+ console.error('' + e)
973
+ throw e
974
+ }
975
+ }
1012
976
 
1013
- // these headers will also have the status,
1014
- // but we want to present the status in a more usual way below
1015
- var status = parsed_headers.headers[':status']
1016
- delete parsed_headers.headers[':status']
977
+ // do the underlying fetch
978
+ try {
979
+ var mux_was_done = await promise_done(mux_promise)
1017
980
 
1018
- // create our own fake response object,
1019
- // to mimik fetch's response object,
1020
- // feeding the user our request data from the multiplexer
1021
- var res = new Response(new ReadableStream({
1022
- async start(controller) {
1023
- try {
1024
- await process_buffers(() => {
1025
- var b = buffers.shift()
1026
- if (!b) return true
1027
- controller.enqueue(b)
1028
- })
1029
- } finally { controller.close() }
981
+ var res = await normal_fetch(url, params)
982
+
983
+ if (res.status === 424 && !mux_was_done) {
984
+ // this error will trigger a retry if the user is using that option
985
+ throw new Error('multiplexer not yet connected')
1030
986
  }
1031
- }), {
1032
- status,
1033
- headers: parsed_headers.headers
1034
- })
1035
987
 
1036
- // add a convenience property for the user to know if
1037
- // this response is being multiplexed
1038
- res.is_multiplexed = true
988
+ // if the response says it's ok,
989
+ // but it's is not a multiplexed response,
990
+ // fall back to as if it was a normal fetch
991
+ if (res.ok && res.status !== 293) return res
992
+
993
+ if (res.status !== 293)
994
+ throw new Error('Could not establish multiplexed request '
995
+ + params.headers.get('multiplex-through')
996
+ + ', got status: ' + res.status)
997
+
998
+ if (res.headers.get('Multiplex-Version') !== multiplex_version)
999
+ throw new Error('Could not establish multiplexed request '
1000
+ + params.headers.get('multiplex-through')
1001
+ + ', got unknown version: '
1002
+ + res.headers.get('Multiplex-Version'))
1003
+
1004
+ // we want to present the illusion that the connection is still open,
1005
+ // and therefor closable with "abort",
1006
+ // so we handle the abort ourselves to close the multiplexed request
1007
+ params.signal?.addEventListener('abort', () =>
1008
+ unset(create_abort_error('request aborted')))
1009
+
1010
+ // first, we need to listen for the headers..
1011
+ var headers_buffer = new Uint8Array()
1012
+ var parsed_headers = await process_buffers(() => {
1013
+ // check if the request has been closed
1014
+ var request_ended = !buffers[buffers.length - 1]
1015
+ if (request_ended) buffers.pop()
1016
+
1017
+ // aggregate all the new buffers into our big headers_buffer
1018
+ headers_buffer = concat_buffers([headers_buffer, ...buffers])
1019
+ buffers = []
1020
+
1021
+ // and if the request had ended, put that information back
1022
+ if (request_ended) buffers.push(null)
1023
+
1024
+ // try parsing what we got so far as headers..
1025
+ var x = parse_headers(headers_buffer)
1026
+
1027
+ // how did it go?
1028
+ if (x.result === 'error') {
1029
+ // if we got an error, give up
1030
+ console.log(`headers_buffer: ` + new TextDecoder().decode(headers_buffer))
1031
+ throw new Error('error parsing headers')
1032
+ } else if (x.result === 'waiting') {
1033
+ if (request_ended)
1034
+ throw new Error('Multiplexed request ended before headers received.')
1035
+ } else return x
1036
+ })
1039
1037
 
1040
- // return the fake response object
1041
- return res
1042
- } catch (e) {
1043
- // if we had an error, be sure to unregister ourselves
1044
- unset(e)
1045
- throw e
1038
+ // put the bytes left over from the header back
1039
+ if (parsed_headers.input.length) buffers.unshift(parsed_headers.input)
1040
+
1041
+ // these headers will also have the status,
1042
+ // but we want to present the status in a more usual way below
1043
+ var status = parsed_headers.headers[':status']
1044
+ delete parsed_headers.headers[':status']
1045
+
1046
+ // create our own fake response object,
1047
+ // to mimik fetch's response object,
1048
+ // feeding the user our request data from the multiplexer
1049
+ var res = new Response(new ReadableStream({
1050
+ async start(controller) {
1051
+ try {
1052
+ await process_buffers(() => {
1053
+ var b = buffers.shift()
1054
+ if (!b) return true
1055
+ controller.enqueue(b)
1056
+ })
1057
+ } finally { controller.close() }
1058
+ }
1059
+ }), {
1060
+ status,
1061
+ headers: parsed_headers.headers
1062
+ })
1063
+
1064
+ // add a convenience property for the user to know if
1065
+ // this response is being multiplexed
1066
+ res.is_multiplexed = true
1067
+
1068
+ // return the fake response object
1069
+ return res
1070
+ } catch (e) {
1071
+ // if we had an error, be sure to unregister ourselves
1072
+ unset(e)
1073
+ throw e
1074
+ }
1046
1075
  }
1047
- }
1048
- })()
1076
+ })()
1049
1077
 
1050
1078
  // call the special fetch function for the multiplexer
1051
1079
  return await (await multiplex_fetch.multiplexers[mux_key])(url, params)
@@ -1183,6 +1211,10 @@ async function promise_done(promise) {
1183
1211
  return ret !== pending
1184
1212
  }
1185
1213
 
1214
+ function random_base64url(n) {
1215
+ return [...crypto.getRandomValues(new Uint8Array(n))].map(x => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'[x % 64]).join('')
1216
+ }
1217
+
1186
1218
  // ****************************
1187
1219
  // Exports
1188
1220
  // ****************************
@@ -269,8 +269,7 @@ function braidify (req, res, next) {
269
269
  res.writeHead(409, 'Conflict', {'Content-Type': 'application/json'})
270
270
  return res.end(JSON.stringify({
271
271
  error: 'Multiplexer already exists',
272
- message: `Cannot create duplicate multiplexer with ID '${multiplexer}'`,
273
- details: 'This multiplexer ID must be unique'
272
+ details: `Cannot create duplicate multiplexer with ID '${multiplexer}'`
274
273
  }))
275
274
  }
276
275
 
@@ -344,9 +343,9 @@ function braidify (req, res, next) {
344
343
  if (m.requests.has(request)) {
345
344
  res.writeHead(409, 'Conflict', {'Content-Type': 'application/json'})
346
345
  return res.end(JSON.stringify({
347
- error: 'Request already exists',
348
- message: `Cannot create duplicate request with ID '${request}'`,
349
- details: 'This request ID must be unique'
346
+ error: 'Request already multiplexed',
347
+ details: `Cannot multiplex request with duplicate ID '`
348
+ + request + `' for multiplexer '` + multiplexer + `'`
350
349
  }))
351
350
  }
352
351
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "1.3.44",
3
+ "version": "1.3.46",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"