braid-http 0.0.1 → 0.1.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/braid-http-client.js +59 -15
- package/braid-http-server.js +176 -102
- package/index.js +1 -1
- package/index.mjs +3 -3
- package/package.json +1 -1
- package/readme.md +14 -7
package/braid-http-client.js
CHANGED
|
@@ -136,7 +136,7 @@ if (is_nodejs) {
|
|
|
136
136
|
normal_fetch = window.fetch
|
|
137
137
|
AbortController = window.AbortController
|
|
138
138
|
Headers = window.Headers
|
|
139
|
-
window.fetch = braid_fetch
|
|
139
|
+
// window.fetch = braid_fetch
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
async function braid_fetch (url, params = {}) {
|
|
@@ -162,16 +162,30 @@ async function braid_fetch (url, params = {}) {
|
|
|
162
162
|
|
|
163
163
|
// Prepare patches
|
|
164
164
|
if (params.patches) {
|
|
165
|
-
console.assert(Array.isArray(params.patches), 'Patches must be array')
|
|
166
165
|
console.assert(!params.body, 'Cannot send both patches and body')
|
|
166
|
+
console.assert(typeof params.patches === 'object', 'Patches must be object or array')
|
|
167
|
+
|
|
168
|
+
// We accept a single patch as an array of one patch
|
|
169
|
+
if (!Array.isArray(params.patches))
|
|
170
|
+
params.patches = [params.patches]
|
|
171
|
+
|
|
172
|
+
// If just one patch, send it directly!
|
|
173
|
+
if (params.patches.length === 1) {
|
|
174
|
+
let patch = params.patches[0]
|
|
175
|
+
params.headers.set('Content-Range', `${patch.unit} ${patch.range}`)
|
|
176
|
+
params.headers.set('Content-Length', `${patch.content.length}`)
|
|
177
|
+
params.body = patch.content
|
|
178
|
+
}
|
|
167
179
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
180
|
+
// Multiple patches get sent within a Patches: N block
|
|
181
|
+
else {
|
|
182
|
+
params.headers.set('Patches', params.patches.length)
|
|
183
|
+
params.body = (params.patches).map(patch => {
|
|
184
|
+
var length = `content-length: ${patch.content.length}`
|
|
185
|
+
var range = `content-range: ${patch.unit} ${patch.range}`
|
|
186
|
+
return `${length}\r\n${range}\r\n\r\n${patch.content}\r\n`
|
|
187
|
+
}).join('\r\n')
|
|
188
|
+
}
|
|
175
189
|
}
|
|
176
190
|
|
|
177
191
|
// Wrap the AbortController with a new one that we control.
|
|
@@ -482,19 +496,51 @@ function parse_headers (input) {
|
|
|
482
496
|
return { result: 'success', headers, input }
|
|
483
497
|
}
|
|
484
498
|
|
|
499
|
+
// Content-range is of the form '<unit> <range>' e.g. 'json .index'
|
|
500
|
+
var content_range_regex = /(\S+) (.*)/
|
|
485
501
|
function parse_body (state) {
|
|
502
|
+
|
|
486
503
|
// Parse Body Snapshot
|
|
487
504
|
|
|
488
505
|
var content_length = parseInt(state.headers['content-length'])
|
|
489
|
-
if (content_length
|
|
506
|
+
if (!isNaN(content_length)) {
|
|
507
|
+
|
|
508
|
+
// We've read a Content-Length, so we have a block to parse
|
|
490
509
|
if (content_length > state.input.length) {
|
|
510
|
+
// But we haven't received the whole block yet
|
|
491
511
|
state.result = 'waiting'
|
|
492
512
|
return state
|
|
493
513
|
}
|
|
494
514
|
|
|
515
|
+
// We have the whole block!
|
|
495
516
|
var consumed_length = content_length + 2
|
|
496
517
|
state.result = 'success'
|
|
497
|
-
|
|
518
|
+
|
|
519
|
+
// If we have a content-range, then this is a patch
|
|
520
|
+
if (state.headers['content-range']) {
|
|
521
|
+
var match = state.headers['content-range'].match(content_range_regex)
|
|
522
|
+
if (!match)
|
|
523
|
+
return {
|
|
524
|
+
result: 'error',
|
|
525
|
+
message: 'cannot parse content-range',
|
|
526
|
+
range: state.headers['content-range']
|
|
527
|
+
}
|
|
528
|
+
state.patches = [{
|
|
529
|
+
unit: match[1],
|
|
530
|
+
range: match[2],
|
|
531
|
+
content: state.input.substring(0, content_length),
|
|
532
|
+
|
|
533
|
+
// Question: Perhaps we should include headers here, like we do for
|
|
534
|
+
// the Patches: N headers below?
|
|
535
|
+
|
|
536
|
+
// headers: state.headers
|
|
537
|
+
}]
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Otherwise, this is a snapshot body
|
|
541
|
+
else
|
|
542
|
+
state.body = state.input.substring(0, content_length)
|
|
543
|
+
|
|
498
544
|
state.input = state.input.substring(consumed_length)
|
|
499
545
|
return state
|
|
500
546
|
}
|
|
@@ -535,7 +581,7 @@ function parse_body (state) {
|
|
|
535
581
|
state.input = parsed.input
|
|
536
582
|
}
|
|
537
583
|
|
|
538
|
-
// Todo: support
|
|
584
|
+
// Todo: support custom patches, not just range-patch
|
|
539
585
|
|
|
540
586
|
// Parse Range Patch format
|
|
541
587
|
{
|
|
@@ -561,9 +607,7 @@ function parse_body (state) {
|
|
|
561
607
|
return state
|
|
562
608
|
}
|
|
563
609
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
var match = last_patch.headers['content-range'].match(/(\S+) (.*)/)
|
|
610
|
+
var match = last_patch.headers['content-range'].match(content_range_regex)
|
|
567
611
|
if (!match)
|
|
568
612
|
return {
|
|
569
613
|
result: 'error',
|
package/braid-http-server.js
CHANGED
|
@@ -1,31 +1,62 @@
|
|
|
1
1
|
var assert = require('assert')
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// Return a string of patches in pseudoheader format.
|
|
4
|
+
//
|
|
5
|
+
// The `patches` argument can be:
|
|
6
|
+
// - Array of patches
|
|
7
|
+
// - A single patch
|
|
8
|
+
//
|
|
9
|
+
// Multiple patches are generated like:
|
|
10
|
+
//
|
|
11
|
+
// Patches: n
|
|
12
|
+
//
|
|
13
|
+
// content-length: 21
|
|
14
|
+
// content-range: json .range
|
|
15
|
+
//
|
|
16
|
+
// {"some": "json object"}
|
|
17
|
+
//
|
|
18
|
+
// content-length: x
|
|
19
|
+
// ...
|
|
20
|
+
//
|
|
21
|
+
// A single patch is generated like:
|
|
22
|
+
//
|
|
23
|
+
// content-length: 21
|
|
24
|
+
// content-range: json .range
|
|
25
|
+
//
|
|
26
|
+
// {"some": "json object"}
|
|
27
|
+
//
|
|
4
28
|
function generate_patches(res, patches) {
|
|
29
|
+
|
|
30
|
+
// `patches` must be an object or an array
|
|
31
|
+
assert(typeof patches === 'object')
|
|
32
|
+
|
|
33
|
+
// An array of one patch behaves like a single patch
|
|
34
|
+
if (!Array.isArray(patches))
|
|
35
|
+
var patches = [patches]
|
|
36
|
+
|
|
5
37
|
for (let patch of patches) {
|
|
6
38
|
assert(typeof patch.unit === 'string')
|
|
7
39
|
assert(typeof patch.range === 'string')
|
|
8
40
|
assert(typeof patch.content === 'string')
|
|
9
41
|
}
|
|
10
42
|
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
//
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
//
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
result +=
|
|
24
|
-
|
|
25
|
-
content-range: ${patch.unit} ${patch.range}\r
|
|
43
|
+
// Build up the string as a result
|
|
44
|
+
var result = ''
|
|
45
|
+
|
|
46
|
+
// Add `Patches: N` header if we have multiple patches
|
|
47
|
+
if (patches.length > 1)
|
|
48
|
+
result += `Patches: ${patches.length}\r\n\r\n`
|
|
49
|
+
|
|
50
|
+
// Generate each patch
|
|
51
|
+
patches.forEach((patch, i) => {
|
|
52
|
+
if (i > 0)
|
|
53
|
+
result += '\r\n\r\n'
|
|
54
|
+
|
|
55
|
+
result += `Content-Length: ${patch.content.length}\r
|
|
56
|
+
Content-Range: ${patch.unit} ${patch.range}\r
|
|
26
57
|
\r
|
|
27
|
-
${patch.content}
|
|
28
|
-
|
|
58
|
+
${patch.content}`
|
|
59
|
+
})
|
|
29
60
|
return result
|
|
30
61
|
}
|
|
31
62
|
|
|
@@ -33,81 +64,118 @@ ${patch.content}\r
|
|
|
33
64
|
// This function reads num_patches in pseudoheader format from a
|
|
34
65
|
// ReadableStream and then fires a callback when they're finished.
|
|
35
66
|
function parse_patches (req, cb) {
|
|
36
|
-
|
|
37
|
-
// Content-Range is still set, nonetheless.
|
|
38
|
-
|
|
39
|
-
var num_patches = req.headers.patches,
|
|
40
|
-
stream = req
|
|
41
|
-
|
|
42
|
-
let patches = []
|
|
43
|
-
let buffer = ""
|
|
44
|
-
if (num_patches === 0)
|
|
45
|
-
return cb(patches)
|
|
46
|
-
|
|
47
|
-
stream.on('data', function parse (chunk) {
|
|
48
|
-
// Merge the latest chunk into our buffer
|
|
49
|
-
buffer = (buffer + chunk)
|
|
50
|
-
|
|
51
|
-
// We might have an extra newline at the start. (mike: why?)
|
|
52
|
-
buffer = buffer.trimStart()
|
|
53
|
-
|
|
54
|
-
while (patches.length < num_patches) {
|
|
55
|
-
// First parse the patch headers. It ends with a double-newline.
|
|
56
|
-
// Let's see where that is.
|
|
57
|
-
var headers_end = buffer.match(/(\r?\n)(\r?\n)/)
|
|
58
|
-
|
|
59
|
-
// Give up if we don't have a set of headers yet.
|
|
60
|
-
if (!headers_end)
|
|
61
|
-
return
|
|
62
|
-
|
|
63
|
-
// Now we know where things end
|
|
64
|
-
var first_newline = headers_end[1],
|
|
65
|
-
headers_length = headers_end.index + first_newline.length,
|
|
66
|
-
blank_line = headers_end[2]
|
|
67
|
-
|
|
68
|
-
// Now let's parse those headers.
|
|
69
|
-
var headers = require('parse-headers')(
|
|
70
|
-
buffer.substring(0, headers_length)
|
|
71
|
-
)
|
|
72
|
-
|
|
73
|
-
// We require `content-length` to declare the length of the patch.
|
|
74
|
-
if (!('content-length' in headers)) {
|
|
75
|
-
// Print a nice error if it's missing
|
|
76
|
-
console.error('No content-length in', JSON.stringify(headers))
|
|
77
|
-
process.exit(1)
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
var body_length = parseInt(headers['content-length'])
|
|
81
|
-
|
|
82
|
-
// Give up if we don't have the full patch yet.
|
|
83
|
-
if (buffer.length < headers_length + blank_line.length + body_length)
|
|
84
|
-
return
|
|
85
|
-
|
|
86
|
-
// XX Todo: support custom patch types beyond content-range.
|
|
67
|
+
var num_patches = req.headers.patches
|
|
87
68
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
var patch_content =
|
|
91
|
-
buffer.substring(headers_length + blank_line.length,
|
|
92
|
-
headers_length + blank_line.length + body_length)
|
|
69
|
+
// Parse a single patch from the request body
|
|
70
|
+
if (num_patches === undefined) {
|
|
93
71
|
|
|
94
|
-
|
|
95
|
-
|
|
72
|
+
// We only support range patches right now, so there must be a
|
|
73
|
+
// Content-Range header.
|
|
74
|
+
assert(req.headers['content-range'], 'No patches to parse: need `Patches: N` or `Content-Range:` header in ' + JSON.stringify(req.headers))
|
|
96
75
|
|
|
97
|
-
|
|
76
|
+
// Parse the Content-Range header
|
|
77
|
+
var match = req.headers['content-range'].match(/(\S+) (.*)/)
|
|
78
|
+
if (!match) {
|
|
79
|
+
console.error('Cannot parse Content-Range in', JSON.stringify(headers))
|
|
80
|
+
process.exit(1)
|
|
98
81
|
}
|
|
82
|
+
var [unit, range] = match.slice(1)
|
|
83
|
+
|
|
84
|
+
// The contents of the patch is in the request body
|
|
85
|
+
var buffer = ''
|
|
86
|
+
// Read the body one chunk at a time
|
|
87
|
+
req.on('data', chunk => buffer = buffer + chunk)
|
|
88
|
+
// Then return it
|
|
89
|
+
req.on('end', () => {
|
|
90
|
+
patches = [{unit, range, content: buffer}]
|
|
91
|
+
cb(patches)
|
|
92
|
+
})
|
|
93
|
+
}
|
|
99
94
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
//
|
|
107
|
-
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
95
|
+
// Parse multiple patches within a Patches: N block
|
|
96
|
+
else {
|
|
97
|
+
num_patches = parseInt(num_patches)
|
|
98
|
+
let patches = []
|
|
99
|
+
let buffer = ""
|
|
100
|
+
|
|
101
|
+
// We check to send send patches each time we parse one. But if there
|
|
102
|
+
// are zero to parse, we will never check to send them.
|
|
103
|
+
if (num_patches === 0)
|
|
104
|
+
return cb([])
|
|
105
|
+
|
|
106
|
+
req.on('data', function parse (chunk) {
|
|
107
|
+
|
|
108
|
+
// Merge the latest chunk into our buffer
|
|
109
|
+
buffer = (buffer + chunk)
|
|
110
|
+
|
|
111
|
+
while (patches.length < num_patches) {
|
|
112
|
+
// We might have extra newlines at the start, because patches
|
|
113
|
+
// can be separated by arbitrary numbers of newlines
|
|
114
|
+
buffer = buffer.trimStart()
|
|
115
|
+
|
|
116
|
+
// First parse the patch headers. It ends with a double-newline.
|
|
117
|
+
// Let's see where that is.
|
|
118
|
+
var headers_end = buffer.match(/(\r?\n)(\r?\n)/)
|
|
119
|
+
|
|
120
|
+
// Give up if we don't have a set of headers yet.
|
|
121
|
+
if (!headers_end)
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
// Now we know where things end
|
|
125
|
+
var first_newline = headers_end[1],
|
|
126
|
+
headers_length = headers_end.index + first_newline.length,
|
|
127
|
+
blank_line = headers_end[2]
|
|
128
|
+
|
|
129
|
+
// Now let's parse those headers.
|
|
130
|
+
var headers = require('parse-headers')(
|
|
131
|
+
buffer.substring(0, headers_length)
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
// We require `content-length` to declare the length of the patch.
|
|
135
|
+
if (!('content-length' in headers)) {
|
|
136
|
+
// Print a nice error if it's missing
|
|
137
|
+
console.error('No content-length in', JSON.stringify(headers),
|
|
138
|
+
'from', {buffer, headers_length})
|
|
139
|
+
process.exit(1)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
var body_length = parseInt(headers['content-length'])
|
|
143
|
+
|
|
144
|
+
// Give up if we don't have the full patch yet.
|
|
145
|
+
if (buffer.length < headers_length + blank_line.length + body_length)
|
|
146
|
+
return
|
|
147
|
+
|
|
148
|
+
// XX Todo: support custom patch types beyond content-range.
|
|
149
|
+
|
|
150
|
+
// Content-range is of the form '<unit> <range>' e.g. 'json .index'
|
|
151
|
+
var match = headers['content-range'].match(/(\S+) (.*)/)
|
|
152
|
+
if (!match) {
|
|
153
|
+
console.error('Cannot parse Content-Range in', JSON.stringify(headers))
|
|
154
|
+
process.exit(1)
|
|
155
|
+
}
|
|
156
|
+
var [unit, range] = match.slice(1)
|
|
157
|
+
var patch_content =
|
|
158
|
+
buffer.substring(headers_length + blank_line.length,
|
|
159
|
+
headers_length + blank_line.length + body_length)
|
|
160
|
+
|
|
161
|
+
// We've got our patch!
|
|
162
|
+
patches.push({unit, range, content: patch_content})
|
|
163
|
+
|
|
164
|
+
buffer = buffer.substring(headers_length + blank_line.length + body_length)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// We got all the patches! Pause the stream and tell the callback!
|
|
168
|
+
req.pause()
|
|
169
|
+
cb(patches)
|
|
170
|
+
})
|
|
171
|
+
req.on('end', () => {
|
|
172
|
+
// If the stream ends before we get everything, then return what we
|
|
173
|
+
// did receive
|
|
174
|
+
console.error('Request stream ended!')
|
|
175
|
+
if (patches.length !== num_patches)
|
|
176
|
+
console.error(`Got an incomplete PUT: ${patches.length}/${num_patches} patches were received`)
|
|
177
|
+
})
|
|
178
|
+
}
|
|
111
179
|
}
|
|
112
180
|
|
|
113
181
|
function braidify (req, res, next) {
|
|
@@ -116,7 +184,6 @@ function braidify (req, res, next) {
|
|
|
116
184
|
// First, declare that we support Patches and JSON ranges.
|
|
117
185
|
res.setHeader('Range-Request-Allow-Methods', 'PATCH, PUT')
|
|
118
186
|
res.setHeader('Range-Request-Allow-Units', 'json')
|
|
119
|
-
res.setHeader("Patches", "OK")
|
|
120
187
|
|
|
121
188
|
// Extract braid info from headers
|
|
122
189
|
var version = req.headers.version && JSON.parse(req.headers.version),
|
|
@@ -163,6 +230,7 @@ function braidify (req, res, next) {
|
|
|
163
230
|
res.statusCode = 209
|
|
164
231
|
res.setHeader("subscribe", req.headers.subscribe)
|
|
165
232
|
res.setHeader('cache-control', 'no-cache, no-transform')
|
|
233
|
+
res.setHeader('transfer-encoding', '')
|
|
166
234
|
|
|
167
235
|
var connected = true
|
|
168
236
|
function disconnected (x) {
|
|
@@ -198,7 +266,7 @@ function send_version(res, data, url, peer) {
|
|
|
198
266
|
}
|
|
199
267
|
function write_body (body) {
|
|
200
268
|
if (res.isSubscription)
|
|
201
|
-
res.write('\r\n' + body
|
|
269
|
+
res.write('\r\n' + body)
|
|
202
270
|
else
|
|
203
271
|
res.write(body)
|
|
204
272
|
}
|
|
@@ -211,16 +279,26 @@ function send_version(res, data, url, peer) {
|
|
|
211
279
|
assert(typeof body === 'string')
|
|
212
280
|
else {
|
|
213
281
|
assert(patches !== undefined)
|
|
214
|
-
|
|
282
|
+
assert(patches !== null)
|
|
283
|
+
assert(typeof patches === 'object')
|
|
284
|
+
if (Array.isArray(patches))
|
|
285
|
+
patches.forEach(p => assert(typeof p.content === 'string'))
|
|
215
286
|
}
|
|
287
|
+
assert(body || patches, 'Missing body or patches')
|
|
288
|
+
assert(!(body && patches), 'Cannot send both body and patches')
|
|
216
289
|
|
|
217
290
|
// Write the headers or virtual headers
|
|
218
291
|
for (var [header, value] of Object.entries(data)) {
|
|
292
|
+
header = header.toLowerCase()
|
|
293
|
+
|
|
219
294
|
// Version and Parents get output in the Structured Headers format
|
|
220
|
-
if (header === 'version')
|
|
295
|
+
if (header === 'version') {
|
|
296
|
+
header = 'Version' // Capitalize for prettiness
|
|
221
297
|
value = JSON.stringify(value)
|
|
222
|
-
else if (header === 'parents')
|
|
298
|
+
} else if (header === 'parents') {
|
|
299
|
+
header = 'Parents' // Capitalize for prettiness
|
|
223
300
|
value = parents.map(JSON.stringify).join(", ")
|
|
301
|
+
}
|
|
224
302
|
|
|
225
303
|
// We don't output patches or body yet
|
|
226
304
|
else if (header === 'patches' || header == 'body')
|
|
@@ -230,20 +308,16 @@ function send_version(res, data, url, peer) {
|
|
|
230
308
|
}
|
|
231
309
|
|
|
232
310
|
// Write the patches or body
|
|
233
|
-
if (
|
|
234
|
-
|
|
235
|
-
else if (typeof body === 'string') {
|
|
236
|
-
set_header('content-length', body.length)
|
|
311
|
+
if (typeof body === 'string') {
|
|
312
|
+
set_header('Content-Length', body.length)
|
|
237
313
|
write_body(body)
|
|
238
|
-
} else
|
|
239
|
-
|
|
240
|
-
process.exit()
|
|
241
|
-
}
|
|
314
|
+
} else
|
|
315
|
+
res.write(generate_patches(res, patches))
|
|
242
316
|
|
|
243
317
|
// Add a newline to prepare for the next version
|
|
244
318
|
// See also https://github.com/braid-org/braid-spec/issues/73
|
|
245
319
|
if (res.isSubscription) {
|
|
246
|
-
var extra_newlines =
|
|
320
|
+
var extra_newlines = 1
|
|
247
321
|
if (res.is_firefox)
|
|
248
322
|
// Work around Firefox network buffering bug
|
|
249
323
|
// See https://github.com/braid-org/braidjs/issues/15
|
package/index.js
CHANGED
package/index.mjs
CHANGED
|
@@ -8,8 +8,8 @@ import braid_client from './braid-http-client.js'
|
|
|
8
8
|
import braid_server from './braid-http-server.js'
|
|
9
9
|
|
|
10
10
|
var fetch = braid_client.fetch,
|
|
11
|
-
|
|
11
|
+
http_client = braid_client.http,
|
|
12
12
|
http_server = braid_server
|
|
13
13
|
|
|
14
|
-
export { fetch,
|
|
15
|
-
export default { fetch,
|
|
14
|
+
export { fetch, http_client, http_server }
|
|
15
|
+
export default { fetch, http_client, http_server }
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Braid-HTTP
|
|
2
2
|
|
|
3
|
-
This polyfill library implements the [Braid-HTTP v03 protocol](https://github.com/braid-org/braid-spec/blob/master/draft-toomim-httpbis-braid-http-03.txt) in Javascript. It
|
|
3
|
+
This polyfill library implements the [Braid-HTTP v03 protocol](https://github.com/braid-org/braid-spec/blob/master/draft-toomim-httpbis-braid-http-03.txt) in Javascript. It gives browsers a `braid_fetch()` drop-in replacement for the `fetch()` API, and gives nodejs an `http` plugin, allowing them to speak Braid in a simple way.
|
|
4
4
|
|
|
5
5
|
Developed in [braid.org](https://braid.org).
|
|
6
6
|
|
|
@@ -11,6 +11,10 @@ Browsers:
|
|
|
11
11
|
|
|
12
12
|
```html
|
|
13
13
|
<script src="https://unpkg.com/braid-http/braid-http-client.js"></script>
|
|
14
|
+
<script>
|
|
15
|
+
// To live on the cutting edge, you can now replace the browser's fetch() if desired:
|
|
16
|
+
// window.fetch = braid_fetch
|
|
17
|
+
</script>
|
|
14
18
|
```
|
|
15
19
|
|
|
16
20
|
Node.js:
|
|
@@ -19,12 +23,14 @@ Node.js:
|
|
|
19
23
|
npm install braid-http
|
|
20
24
|
```
|
|
21
25
|
|
|
22
|
-
Then in your node.js code:
|
|
23
|
-
|
|
24
26
|
```javascript
|
|
27
|
+
// Import with require()
|
|
25
28
|
require('braid-http').fetch // A polyfill for require('node-fetch')
|
|
26
|
-
require('braid-http').
|
|
29
|
+
require('braid-http').http_client // A polyfill for require('http') clients
|
|
27
30
|
require('braid-http').http_server // A polyfill for require('http') servers
|
|
31
|
+
|
|
32
|
+
// Or as es6 module
|
|
33
|
+
import {fetch, http_client, http_server} from 'braid-http'
|
|
28
34
|
```
|
|
29
35
|
|
|
30
36
|
## Using it in Browsers
|
|
@@ -96,7 +102,8 @@ async function connect () {
|
|
|
96
102
|
```javascript
|
|
97
103
|
async function connect () {
|
|
98
104
|
try {
|
|
99
|
-
|
|
105
|
+
var subscription_iterator = fetch('/chat', {subscribe: true}).subscription
|
|
106
|
+
for await (var v of subscription_iterator) {
|
|
100
107
|
// Updates might come in the form of patches:
|
|
101
108
|
if (v.patches)
|
|
102
109
|
chat = apply_patches(v.patches, chat)
|
|
@@ -201,10 +208,10 @@ require('http').createServer(app).listen(8583)
|
|
|
201
208
|
// Use this line if necessary for self-signed certs
|
|
202
209
|
// process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0
|
|
203
210
|
|
|
204
|
-
var https = require('braid-http').
|
|
211
|
+
var https = require('braid-http').http_client(require('https'))
|
|
205
212
|
// or:
|
|
206
213
|
// import braid_http from 'braid-http'
|
|
207
|
-
// https = braid_http.
|
|
214
|
+
// https = braid_http.http_client(require('https'))
|
|
208
215
|
|
|
209
216
|
https.get(
|
|
210
217
|
'https://braid.org/chat',
|