braid-http 1.3.48 → 1.3.50
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/braid-http-client.js +89 -69
- package/package.json +1 -1
package/braid-http-client.js
CHANGED
|
@@ -315,7 +315,7 @@ async function braid_fetch (url, params = {}) {
|
|
|
315
315
|
(params.headers.has('subscribe') &&
|
|
316
316
|
braid_fetch.subscription_counts?.[origin] >
|
|
317
317
|
(!mux_params ? 1 : (mux_params.after ?? 0))))) {
|
|
318
|
-
res = await multiplex_fetch(url, params, mux_params)
|
|
318
|
+
res = await multiplex_fetch(url, params, mux_params, underlying_aborter)
|
|
319
319
|
} else
|
|
320
320
|
res = await normal_fetch(url, params)
|
|
321
321
|
|
|
@@ -830,9 +830,72 @@ function parse_body (state) {
|
|
|
830
830
|
}
|
|
831
831
|
}
|
|
832
832
|
|
|
833
|
+
|
|
834
|
+
// The "extra_headers" field is returned to the client on any *update* or
|
|
835
|
+
// *patch* to include any headers that we've received, but don't have braid
|
|
836
|
+
// semantics for.
|
|
837
|
+
//
|
|
838
|
+
// This function creates that hash from a headers object, by filtering out all
|
|
839
|
+
// known headers.
|
|
840
|
+
function extra_headers (headers) {
|
|
841
|
+
// Clone headers
|
|
842
|
+
var result = Object.assign({}, headers)
|
|
843
|
+
|
|
844
|
+
// Remove the non-extra parts
|
|
845
|
+
var known_headers = ['version', 'parents', 'patches',
|
|
846
|
+
'content-length', 'content-range', ':status']
|
|
847
|
+
for (var i = 0; i < known_headers.length; i++)
|
|
848
|
+
delete result[known_headers[i]]
|
|
849
|
+
|
|
850
|
+
// Return undefined if we deleted them all
|
|
851
|
+
if (Object.keys(result).length === 0)
|
|
852
|
+
return undefined
|
|
853
|
+
|
|
854
|
+
return result
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function get_binary_length(x) {
|
|
858
|
+
return x instanceof ArrayBuffer ? x.byteLength :
|
|
859
|
+
x instanceof Uint8Array ? x.length :
|
|
860
|
+
x instanceof Blob ? x.size : undefined
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
function deep_copy(x) {
|
|
864
|
+
if (x === null || typeof x !== 'object') return x
|
|
865
|
+
if (Array.isArray(x)) return x.map(x => deep_copy(x))
|
|
866
|
+
if (Object.prototype.toString.call(x) === '[object Object]')
|
|
867
|
+
return Object.fromEntries(Object.entries(x).map(([k, x]) => [k, deep_copy(x)]))
|
|
868
|
+
return x
|
|
869
|
+
}
|
|
870
|
+
|
|
871
|
+
function ascii_ify(s) {
|
|
872
|
+
return s.replace(/[^\x20-\x7E]/g, c => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'))
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
function create_abort_error(msg) {
|
|
876
|
+
var e = new Error(msg)
|
|
877
|
+
e.name = 'AbortError'
|
|
878
|
+
return e
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
async function promise_done(promise) {
|
|
882
|
+
var pending = {}
|
|
883
|
+
var ret = await Promise.race([promise, Promise.resolve(pending)])
|
|
884
|
+
return ret !== pending
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
function random_base64url(n) {
|
|
888
|
+
return [...crypto.getRandomValues(new Uint8Array(n))].map(x => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'[x % 64]).join('')
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
|
|
892
|
+
// ****************************
|
|
893
|
+
// Multiplexing
|
|
894
|
+
// ****************************
|
|
895
|
+
|
|
833
896
|
// multiplex_fetch provides a fetch-like experience for HTTP requests
|
|
834
897
|
// where the result is actually being sent over a separate multiplexed connection.
|
|
835
|
-
async function multiplex_fetch(url, params, mux_params) {
|
|
898
|
+
async function multiplex_fetch(url, params, mux_params, aborter) {
|
|
836
899
|
var multiplex_version = '1.0'
|
|
837
900
|
|
|
838
901
|
var origin = new URL(url, typeof document !== 'undefined' ? document.baseURI : undefined).origin
|
|
@@ -894,7 +957,8 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
894
957
|
})
|
|
895
958
|
if (r.status === 409) {
|
|
896
959
|
var e = await r.json()
|
|
897
|
-
if (e.error === 'Multiplexer already exists')
|
|
960
|
+
if (e.error === 'Multiplexer already exists')
|
|
961
|
+
return cleanup(new Error(e.error))
|
|
898
962
|
}
|
|
899
963
|
if (!r.ok || r.headers.get('Multiplex-Version') !== multiplex_version)
|
|
900
964
|
throw 'bad'
|
|
@@ -908,7 +972,8 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
908
972
|
retry: true})
|
|
909
973
|
if (r.status === 409) {
|
|
910
974
|
var e = await r.json()
|
|
911
|
-
if (e.error === 'Multiplexer already exists')
|
|
975
|
+
if (e.error === 'Multiplexer already exists')
|
|
976
|
+
return cleanup(new Error(e.error))
|
|
912
977
|
}
|
|
913
978
|
if (!r.ok) throw new Error('status not ok: ' + r.status)
|
|
914
979
|
if (r.headers.get('Multiplex-Version') !== multiplex_version)
|
|
@@ -919,13 +984,13 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
919
984
|
// fallback to normal fetch if multiplexed connection fails
|
|
920
985
|
console.error(`Could not establish multiplexer.\n`
|
|
921
986
|
+ `Got error: ${e}.\nFalling back to normal connection.`)
|
|
922
|
-
|
|
987
|
+
cleanup(e, true)
|
|
988
|
+
return false
|
|
923
989
|
}
|
|
924
990
|
}
|
|
925
991
|
|
|
926
992
|
// parse the multiplexed stream,
|
|
927
993
|
// and send messages to the appropriate requests
|
|
928
|
-
var try_deleting = new Set()
|
|
929
994
|
parse_multiplex_stream(r.body.getReader(), async (request, bytes) => {
|
|
930
995
|
if (requests.has(request)) requests.get(request)(bytes)
|
|
931
996
|
else try_deleting_request(request)
|
|
@@ -935,6 +1000,14 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
935
1000
|
// return a "fetch" for this multiplexer
|
|
936
1001
|
return async (url, params) => {
|
|
937
1002
|
|
|
1003
|
+
// if we already know the multiplexer is not working,
|
|
1004
|
+
// then fallback to normal fetch
|
|
1005
|
+
// (unless the user is specifically asking for multiplexing)
|
|
1006
|
+
if ((await promise_done(mux_promise))
|
|
1007
|
+
&& (await mux_promise) === false
|
|
1008
|
+
&& !params.headers.get('multiplex-through'))
|
|
1009
|
+
return await normal_fetch(url, params)
|
|
1010
|
+
|
|
938
1011
|
// make up a new request id (unless it is being overriden)
|
|
939
1012
|
var request = params.headers.get('multiplex-through')?.split('/')[4]
|
|
940
1013
|
?? random_base64url(Math.ceil((mux_params?.id_bits ?? 72) / 6))
|
|
@@ -966,8 +1039,10 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
966
1039
|
|
|
967
1040
|
// tell the multiplexer to send bytes for this request to us
|
|
968
1041
|
requests.set(request, bytes => {
|
|
969
|
-
if (!bytes)
|
|
970
|
-
|
|
1042
|
+
if (!bytes) {
|
|
1043
|
+
buffers.push(bytes)
|
|
1044
|
+
if (mux_error || request_error) aborter.abort()
|
|
1045
|
+
} else if (!mux_error) buffers.push(bytes)
|
|
971
1046
|
bytes_available()
|
|
972
1047
|
})
|
|
973
1048
|
|
|
@@ -982,8 +1057,6 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
982
1057
|
|
|
983
1058
|
// do the underlying fetch
|
|
984
1059
|
try {
|
|
985
|
-
var mux_was_done = await promise_done(mux_promise)
|
|
986
|
-
|
|
987
1060
|
var res = await normal_fetch(url, params)
|
|
988
1061
|
|
|
989
1062
|
if (res.status === 409) {
|
|
@@ -991,7 +1064,7 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
991
1064
|
if (e.error === 'Request already multiplexed') throw new Error(e.error)
|
|
992
1065
|
}
|
|
993
1066
|
|
|
994
|
-
if (res.status === 424
|
|
1067
|
+
if (res.status === 424) {
|
|
995
1068
|
// this error will trigger a retry if the user is using that option
|
|
996
1069
|
throw new Error('multiplexer not yet connected')
|
|
997
1070
|
}
|
|
@@ -1062,7 +1135,10 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
1062
1135
|
try {
|
|
1063
1136
|
await process_buffers(() => {
|
|
1064
1137
|
var b = buffers.shift()
|
|
1065
|
-
if (!b)
|
|
1138
|
+
if (!b) {
|
|
1139
|
+
if (mux_error || request_error) controller.error(mux_error || request_error)
|
|
1140
|
+
return true
|
|
1141
|
+
}
|
|
1066
1142
|
controller.enqueue(b)
|
|
1067
1143
|
})
|
|
1068
1144
|
} finally { controller.close() }
|
|
@@ -1081,7 +1157,7 @@ async function multiplex_fetch(url, params, mux_params) {
|
|
|
1081
1157
|
} catch (e) {
|
|
1082
1158
|
// if we had an error, be sure to unregister ourselves
|
|
1083
1159
|
unset(e)
|
|
1084
|
-
throw e
|
|
1160
|
+
throw mux_error || e
|
|
1085
1161
|
}
|
|
1086
1162
|
}
|
|
1087
1163
|
})()
|
|
@@ -1169,62 +1245,6 @@ function concat_buffers(buffers) {
|
|
|
1169
1245
|
return x
|
|
1170
1246
|
}
|
|
1171
1247
|
|
|
1172
|
-
// The "extra_headers" field is returned to the client on any *update* or
|
|
1173
|
-
// *patch* to include any headers that we've received, but don't have braid
|
|
1174
|
-
// semantics for.
|
|
1175
|
-
//
|
|
1176
|
-
// This function creates that hash from a headers object, by filtering out all
|
|
1177
|
-
// known headers.
|
|
1178
|
-
function extra_headers (headers) {
|
|
1179
|
-
// Clone headers
|
|
1180
|
-
var result = Object.assign({}, headers)
|
|
1181
|
-
|
|
1182
|
-
// Remove the non-extra parts
|
|
1183
|
-
var known_headers = ['version', 'parents', 'patches',
|
|
1184
|
-
'content-length', 'content-range', ':status']
|
|
1185
|
-
for (var i = 0; i < known_headers.length; i++)
|
|
1186
|
-
delete result[known_headers[i]]
|
|
1187
|
-
|
|
1188
|
-
// Return undefined if we deleted them all
|
|
1189
|
-
if (Object.keys(result).length === 0)
|
|
1190
|
-
return undefined
|
|
1191
|
-
|
|
1192
|
-
return result
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
function get_binary_length(x) {
|
|
1196
|
-
return x instanceof ArrayBuffer ? x.byteLength :
|
|
1197
|
-
x instanceof Uint8Array ? x.length :
|
|
1198
|
-
x instanceof Blob ? x.size : undefined
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
function deep_copy(x) {
|
|
1202
|
-
if (x === null || typeof x !== 'object') return x
|
|
1203
|
-
if (Array.isArray(x)) return x.map(x => deep_copy(x))
|
|
1204
|
-
if (Object.prototype.toString.call(x) === '[object Object]')
|
|
1205
|
-
return Object.fromEntries(Object.entries(x).map(([k, x]) => [k, deep_copy(x)]))
|
|
1206
|
-
return x
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
function ascii_ify(s) {
|
|
1210
|
-
return s.replace(/[^\x20-\x7E]/g, c => '\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'))
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
function create_abort_error(msg) {
|
|
1214
|
-
var e = new Error(msg)
|
|
1215
|
-
e.name = 'AbortError'
|
|
1216
|
-
return e
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
async function promise_done(promise) {
|
|
1220
|
-
var pending = {}
|
|
1221
|
-
var ret = await Promise.race([promise, Promise.resolve(pending)])
|
|
1222
|
-
return ret !== pending
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
function random_base64url(n) {
|
|
1226
|
-
return [...crypto.getRandomValues(new Uint8Array(n))].map(x => 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'[x % 64]).join('')
|
|
1227
|
-
}
|
|
1228
1248
|
|
|
1229
1249
|
// ****************************
|
|
1230
1250
|
// Exports
|