braid-http 0.3.1 → 0.3.3
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 +50 -29
- package/braid-http-server.js +7 -7
- package/package.json +1 -1
- package/readme.md +20 -22
package/braid-http-client.js
CHANGED
|
@@ -48,25 +48,26 @@ function braidify_http (http) {
|
|
|
48
48
|
// Always add the `peer` header
|
|
49
49
|
options.headers.peer = options.headers.peer || peer
|
|
50
50
|
|
|
51
|
-
// Wrap the callback to provide our new .on('
|
|
51
|
+
// Wrap the callback to provide our new .on('update', ...) feature
|
|
52
52
|
// on nodejs servers
|
|
53
|
-
var
|
|
53
|
+
var on_update,
|
|
54
54
|
on_error,
|
|
55
55
|
orig_cb = cb
|
|
56
56
|
cb = (res) => {
|
|
57
57
|
res.orig_on = res.on
|
|
58
58
|
res.on = (key, f) => {
|
|
59
59
|
|
|
60
|
-
// Define .on('
|
|
61
|
-
if (key === '
|
|
60
|
+
// Define .on('update', cb)
|
|
61
|
+
if (key === 'update'
|
|
62
|
+
|| key === 'version' /* Deprecated API calls it 'version' */ ) {
|
|
62
63
|
|
|
63
|
-
// If we have an '
|
|
64
|
-
|
|
64
|
+
// If we have an 'update' handler, let's remember it
|
|
65
|
+
on_update = f
|
|
65
66
|
|
|
66
67
|
// And set up a subscription parser
|
|
67
|
-
var parser = subscription_parser((
|
|
68
|
+
var parser = subscription_parser((update, error) => {
|
|
68
69
|
if (!error)
|
|
69
|
-
|
|
70
|
+
on_update && on_update(update)
|
|
70
71
|
else
|
|
71
72
|
on_error && on_error(error)
|
|
72
73
|
})
|
|
@@ -149,13 +150,21 @@ async function braid_fetch (url, params = {}) {
|
|
|
149
150
|
else
|
|
150
151
|
params.headers = new Headers(params.headers)
|
|
151
152
|
|
|
153
|
+
// Sanity check inputs
|
|
154
|
+
if (params.version)
|
|
155
|
+
console.assert(Array.isArray(params.version),
|
|
156
|
+
'fetch(): `version` must be an array')
|
|
157
|
+
if (params.parents)
|
|
158
|
+
console.assert(Array.isArray(params.parents),
|
|
159
|
+
'fetch(): `parents` must be an array')
|
|
160
|
+
|
|
152
161
|
// Always set the peer
|
|
153
162
|
params.headers.set('peer', peer)
|
|
154
163
|
|
|
155
164
|
// We provide some shortcuts for Braid params
|
|
156
165
|
if (params.version)
|
|
157
166
|
params.headers.set('version', params.version.map(JSON.stringify).join(', '))
|
|
158
|
-
if (params.parents
|
|
167
|
+
if (params.parents)
|
|
159
168
|
params.headers.set('parents', params.parents.map(JSON.stringify).join(', '))
|
|
160
169
|
if (params.subscribe)
|
|
161
170
|
params.headers.set('subscribe', 'true')
|
|
@@ -342,7 +351,6 @@ async function handle_fetch_stream (stream, cb) {
|
|
|
342
351
|
// Braid-HTTP Subscription Parser
|
|
343
352
|
// ****************************
|
|
344
353
|
|
|
345
|
-
|
|
346
354
|
var subscription_parser = (cb) => ({
|
|
347
355
|
// A parser keeps some parse state
|
|
348
356
|
state: {input: ''},
|
|
@@ -359,23 +367,18 @@ var subscription_parser = (cb) => ({
|
|
|
359
367
|
|
|
360
368
|
// Now loop through the input and parse until we hit a dead end
|
|
361
369
|
while (this.state.input.trim() !== '') {
|
|
362
|
-
this.state =
|
|
370
|
+
this.state = parse_update (this.state)
|
|
363
371
|
|
|
364
372
|
// Maybe we parsed a version! That's cool!
|
|
365
373
|
if (this.state.result === 'success') {
|
|
366
|
-
let ignore_headers = {
|
|
367
|
-
version: true,
|
|
368
|
-
parents: true,
|
|
369
|
-
patches: true,
|
|
370
|
-
'content-length': true,
|
|
371
|
-
'content-range': true,
|
|
372
|
-
}
|
|
373
374
|
this.cb({
|
|
374
375
|
version: this.state.version,
|
|
375
376
|
parents: this.state.parents,
|
|
376
377
|
body: this.state.body,
|
|
377
378
|
patches: this.state.patches,
|
|
378
|
-
|
|
379
|
+
|
|
380
|
+
// Output extra_headers if there are some
|
|
381
|
+
extra_headers: extra_headers(this.state.headers)
|
|
379
382
|
})
|
|
380
383
|
|
|
381
384
|
// Reset the parser for the next version!
|
|
@@ -410,7 +413,7 @@ var subscription_parser = (cb) => ({
|
|
|
410
413
|
// => {result: 'error', ...} If there is a syntax error in the input
|
|
411
414
|
|
|
412
415
|
|
|
413
|
-
function
|
|
416
|
+
function parse_update (state) {
|
|
414
417
|
// If we don't have headers yet, let's try to parse some
|
|
415
418
|
if (!state.headers) {
|
|
416
419
|
var parsed = parse_headers(state.input)
|
|
@@ -488,7 +491,8 @@ function parse_headers (input) {
|
|
|
488
491
|
// Success! Let's parse special headers
|
|
489
492
|
if ('version' in headers)
|
|
490
493
|
headers.version = JSON.parse('['+headers.version+']')
|
|
491
|
-
|
|
494
|
+
if ('parents' in headers)
|
|
495
|
+
headers.parents = JSON.parse('['+headers.parents+']')
|
|
492
496
|
if ('patches' in headers)
|
|
493
497
|
headers.patches = JSON.parse(headers.patches)
|
|
494
498
|
|
|
@@ -632,13 +636,8 @@ function parse_body (state) {
|
|
|
632
636
|
last_patch.unit = match.unit
|
|
633
637
|
last_patch.range = match.range
|
|
634
638
|
last_patch.content = state.input.substr(0, content_length)
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
last_patch.extra_headers = last_patch.headers
|
|
638
|
-
delete last_patch.headers
|
|
639
|
-
delete last_patch.extra_headers['content-length']
|
|
640
|
-
delete last_patch.extra_headers['content-range']
|
|
641
|
-
if (!Object.keys(last_patch.extra_headers).length) delete last_patch.extra_headers
|
|
639
|
+
last_patch.extra_headers = extra_headers(last_patch.headers)
|
|
640
|
+
delete last_patch.headers // We only keep the extra headers ^^
|
|
642
641
|
|
|
643
642
|
// Consume the parsed input
|
|
644
643
|
state.input = state.input.substring(content_length)
|
|
@@ -655,6 +654,28 @@ function parse_body (state) {
|
|
|
655
654
|
}
|
|
656
655
|
}
|
|
657
656
|
|
|
657
|
+
// The "extra_headers" field is returned to the client on any *update* or
|
|
658
|
+
// *patch* to include any headers that we've received, but don't have braid
|
|
659
|
+
// semantics for.
|
|
660
|
+
//
|
|
661
|
+
// This function creates that hash from a headers object, by filtering out all
|
|
662
|
+
// known headers.
|
|
663
|
+
function extra_headers (headers) {
|
|
664
|
+
// Clone headers
|
|
665
|
+
var result = Object.assign({}, headers)
|
|
666
|
+
|
|
667
|
+
// Remove the non-extra parts
|
|
668
|
+
var known_headers = ['version', 'parents', 'patches',
|
|
669
|
+
'content-length', 'content-range']
|
|
670
|
+
for (var i = 0; i < known_headers.length; i++)
|
|
671
|
+
delete result[known_headers[i]]
|
|
672
|
+
|
|
673
|
+
// Return undefined if we deleted them all
|
|
674
|
+
if (Object.keys(result).length === 0)
|
|
675
|
+
return undefined
|
|
676
|
+
|
|
677
|
+
return result
|
|
678
|
+
}
|
|
658
679
|
|
|
659
680
|
// ****************************
|
|
660
681
|
// Exports
|
|
@@ -665,7 +686,7 @@ if (typeof module !== 'undefined' && module.exports)
|
|
|
665
686
|
fetch: braid_fetch,
|
|
666
687
|
http: braidify_http,
|
|
667
688
|
subscription_parser,
|
|
668
|
-
|
|
689
|
+
parse_update,
|
|
669
690
|
parse_headers,
|
|
670
691
|
parse_body
|
|
671
692
|
}
|
package/braid-http-server.js
CHANGED
|
@@ -195,8 +195,8 @@ function braidify (req, res, next) {
|
|
|
195
195
|
res.setHeader('Range-Request-Allow-Units', 'json')
|
|
196
196
|
|
|
197
197
|
// Extract braid info from headers
|
|
198
|
-
var version = JSON.parse('['+
|
|
199
|
-
parents = JSON.parse('['+
|
|
198
|
+
var version = req.headers.version && JSON.parse('['+req.headers.version+']'),
|
|
199
|
+
parents = req.headers.parents && JSON.parse('['+req.headers.parents+']'),
|
|
200
200
|
peer = req.headers['peer'],
|
|
201
201
|
url = req.url.substr(1)
|
|
202
202
|
|
|
@@ -211,8 +211,8 @@ function braidify (req, res, next) {
|
|
|
211
211
|
req.subscribe = subscribe
|
|
212
212
|
|
|
213
213
|
// Add the braidly request/response helper methods
|
|
214
|
-
res.
|
|
215
|
-
res.
|
|
214
|
+
res.sendUpdate = (stuff) => send_update(res, stuff, req.url, peer)
|
|
215
|
+
res.sendVersion = res.sendUpdate
|
|
216
216
|
req.patches = () => new Promise(
|
|
217
217
|
(done, err) => parse_patches(req, (patches) => done(patches))
|
|
218
218
|
)
|
|
@@ -273,7 +273,7 @@ function braidify (req, res, next) {
|
|
|
273
273
|
next && next()
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
-
function
|
|
276
|
+
function send_update(res, data, url, peer) {
|
|
277
277
|
var {version, parents, patches, patch, body} = data
|
|
278
278
|
|
|
279
279
|
function set_header (key, val) {
|
|
@@ -332,13 +332,13 @@ function send_version(res, data, url, peer) {
|
|
|
332
332
|
for (var [header, value] of Object.entries(data)) {
|
|
333
333
|
header = header.toLowerCase()
|
|
334
334
|
|
|
335
|
-
// Version and Parents get output in the Structured Headers format
|
|
335
|
+
// Version and Parents get output in the Structured Headers format,
|
|
336
|
+
// so we convert `value` from array to comma-separated strings.
|
|
336
337
|
if (header === 'version') {
|
|
337
338
|
header = 'Version' // Capitalize for prettiness
|
|
338
339
|
value = value.map(JSON.stringify).join(", ")
|
|
339
340
|
} else if (header === 'parents') {
|
|
340
341
|
header = 'Parents' // Capitalize for prettiness
|
|
341
|
-
if (value.length == 0) continue // we express no parents as not having the field at all
|
|
342
342
|
value = value.map(JSON.stringify).join(", ")
|
|
343
343
|
}
|
|
344
344
|
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -38,7 +38,7 @@ import {fetch, http_client, http_server} from 'braid-http'
|
|
|
38
38
|
This library adds a `{subscribe: true}` option to `fetch()`, and lets you
|
|
39
39
|
access the result of a subscription with two new fields on the fetch response:
|
|
40
40
|
|
|
41
|
-
- `response.subscribe(
|
|
41
|
+
- `response.subscribe( update => ... )`
|
|
42
42
|
- `response.subscription`: an iterator that can be used with `for await`
|
|
43
43
|
|
|
44
44
|
### Example Subscription with Promises
|
|
@@ -48,16 +48,16 @@ Here is an example of subscribing to a Braid resource using promises:
|
|
|
48
48
|
```javascript
|
|
49
49
|
fetch('https://braid.org/chat', {subscribe: true}).then(
|
|
50
50
|
res => res.subscribe(
|
|
51
|
-
(
|
|
52
|
-
console.log('We got a new
|
|
51
|
+
(update) => {
|
|
52
|
+
console.log('We got a new update!', update)
|
|
53
53
|
// {
|
|
54
|
-
// version: "me",
|
|
54
|
+
// version: ["me"],
|
|
55
55
|
// parents: ["mom", "dad"],
|
|
56
56
|
// patches: [{unit: "json", range: ".foo", content: "3"}]
|
|
57
57
|
// body: "3"
|
|
58
58
|
// }
|
|
59
59
|
//
|
|
60
|
-
// Note that
|
|
60
|
+
// Note that `update` will contain either patches *or* body
|
|
61
61
|
}
|
|
62
62
|
)
|
|
63
63
|
)
|
|
@@ -69,9 +69,9 @@ If you want automatic reconnections, add two error handlers like this:
|
|
|
69
69
|
function connect() {
|
|
70
70
|
fetch('https://braid.org/chat', {subscribe: true}).then(
|
|
71
71
|
res => res.subscribe(
|
|
72
|
-
(
|
|
73
|
-
console.log('We got a new
|
|
74
|
-
// Do something with the
|
|
72
|
+
(update) => {
|
|
73
|
+
console.log('We got a new update!', update)
|
|
74
|
+
// Do something with the update
|
|
75
75
|
},
|
|
76
76
|
e => setTimeout(connect, 1000)
|
|
77
77
|
)
|
|
@@ -86,8 +86,8 @@ connect()
|
|
|
86
86
|
async function connect () {
|
|
87
87
|
try {
|
|
88
88
|
(await fetch('/chat', {subscribe: true})).subscribe(
|
|
89
|
-
(
|
|
90
|
-
// We got a new
|
|
89
|
+
(update) => {
|
|
90
|
+
// We got a new update!
|
|
91
91
|
},
|
|
92
92
|
() => setTimeout(connect, 1000)
|
|
93
93
|
)
|
|
@@ -108,7 +108,7 @@ async function connect () {
|
|
|
108
108
|
if (v.patches)
|
|
109
109
|
chat = apply_patches(v.patches, chat)
|
|
110
110
|
|
|
111
|
-
// Or complete
|
|
111
|
+
// Or complete snapshots:
|
|
112
112
|
else
|
|
113
113
|
// Beware the server doesn't send these yet.
|
|
114
114
|
chat = JSON.parse(v.body)
|
|
@@ -153,7 +153,7 @@ require('http').createServer(
|
|
|
153
153
|
|
|
154
154
|
// Send the current version
|
|
155
155
|
res.sendUpdate({
|
|
156
|
-
version: 'greg',
|
|
156
|
+
version: ['greg'],
|
|
157
157
|
body: JSON.stringify({greg: 'greg'})
|
|
158
158
|
})
|
|
159
159
|
}
|
|
@@ -184,14 +184,14 @@ app.get('/', (req, res) => {
|
|
|
184
184
|
|
|
185
185
|
// Send the current version
|
|
186
186
|
res.sendUpdate({
|
|
187
|
-
version: 'greg',
|
|
187
|
+
version: ['greg'],
|
|
188
188
|
parents: ['gr','eg'],
|
|
189
189
|
body: JSON.stringify({greg: 'greg'})
|
|
190
190
|
})
|
|
191
191
|
|
|
192
192
|
// Or you can send patches like this:
|
|
193
193
|
// res.sendUpdate({
|
|
194
|
-
// version: 'greg',
|
|
194
|
+
// version: ['greg'],
|
|
195
195
|
// parents: ['gr','eg'],
|
|
196
196
|
// patches: [{range: '.greg', unit: 'json', content: '"greg"'}]
|
|
197
197
|
// })
|
|
@@ -217,8 +217,8 @@ https.get(
|
|
|
217
217
|
'https://braid.org/chat',
|
|
218
218
|
{subscribe: true},
|
|
219
219
|
(res) => {
|
|
220
|
-
res.on('
|
|
221
|
-
console.log('well we got one',
|
|
220
|
+
res.on('update', (update) => {
|
|
221
|
+
console.log('well we got one', update)
|
|
222
222
|
})
|
|
223
223
|
}
|
|
224
224
|
)
|
|
@@ -232,15 +232,15 @@ function connect () {
|
|
|
232
232
|
'https://braid.org/chat',
|
|
233
233
|
{subscribe: true},
|
|
234
234
|
(res) => {
|
|
235
|
-
res.on('
|
|
235
|
+
res.on('update', (update) => {
|
|
236
236
|
// {
|
|
237
|
-
// version: "me",
|
|
237
|
+
// version: ["me"],
|
|
238
238
|
// parents: ["mom", "dad"],
|
|
239
239
|
// patches: [{unit: "json", range: ".foo", content: "3"}]
|
|
240
240
|
// body: "3"
|
|
241
241
|
// }
|
|
242
|
-
// //
|
|
243
|
-
console.log('We got a new
|
|
242
|
+
// // Update will contain either patches *or* body, but not both
|
|
243
|
+
console.log('We got a new update!', update)
|
|
244
244
|
})
|
|
245
245
|
|
|
246
246
|
res.on('end', e => setTimeout(connect, 1000))
|
|
@@ -272,5 +272,3 @@ automatically reconnect. (See
|
|
|
272
272
|
[issue #980](https://github.com/node-fetch/node-fetch/issues/980) and
|
|
273
273
|
[#753](https://github.com/node-fetch/node-fetch/issues/753).) We recommend
|
|
274
274
|
using the `http` library (below) for requests on nodejs instead.
|
|
275
|
-
|
|
276
|
-
|