braid-http 0.3.2 → 0.3.4
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 +57 -35
- package/braid-http-server.js +7 -7
- package/package.json +1 -1
- package/readme.md +15 -15
package/braid-http-client.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
var peer = Math.random().toString(36).substr(2)
|
|
1
|
+
// var peer = Math.random().toString(36).substr(2)
|
|
2
2
|
|
|
3
3
|
// ***************************
|
|
4
4
|
// http
|
|
5
5
|
// ***************************
|
|
6
6
|
|
|
7
7
|
function braidify_http (http) {
|
|
8
|
-
// Todo: Wrap .put to add `peer` header
|
|
9
8
|
http.normal_get = http.get
|
|
10
9
|
http.get = function braid_req (arg1, arg2, arg3) {
|
|
11
10
|
var url, options, cb
|
|
@@ -45,28 +44,29 @@ function braidify_http (http) {
|
|
|
45
44
|
if (options.subscribe)
|
|
46
45
|
options.headers.subscribe = 'true'
|
|
47
46
|
|
|
48
|
-
// Always add the `peer` header
|
|
49
|
-
options.headers.peer = options.headers.peer || peer
|
|
47
|
+
// // Always add the `peer` header
|
|
48
|
+
// options.headers.peer = options.headers.peer || peer
|
|
50
49
|
|
|
51
|
-
// Wrap the callback to provide our new .on('
|
|
50
|
+
// Wrap the callback to provide our new .on('update', ...) feature
|
|
52
51
|
// on nodejs servers
|
|
53
|
-
var
|
|
52
|
+
var on_update,
|
|
54
53
|
on_error,
|
|
55
54
|
orig_cb = cb
|
|
56
55
|
cb = (res) => {
|
|
57
56
|
res.orig_on = res.on
|
|
58
57
|
res.on = (key, f) => {
|
|
59
58
|
|
|
60
|
-
// Define .on('
|
|
61
|
-
if (key === '
|
|
59
|
+
// Define .on('update', cb)
|
|
60
|
+
if (key === 'update'
|
|
61
|
+
|| key === 'version' /* Deprecated API calls it 'version' */ ) {
|
|
62
62
|
|
|
63
|
-
// If we have an '
|
|
64
|
-
|
|
63
|
+
// If we have an 'update' handler, let's remember it
|
|
64
|
+
on_update = f
|
|
65
65
|
|
|
66
66
|
// And set up a subscription parser
|
|
67
|
-
var parser = subscription_parser((
|
|
67
|
+
var parser = subscription_parser((update, error) => {
|
|
68
68
|
if (!error)
|
|
69
|
-
|
|
69
|
+
on_update && on_update(update)
|
|
70
70
|
else
|
|
71
71
|
on_error && on_error(error)
|
|
72
72
|
})
|
|
@@ -149,16 +149,26 @@ async function braid_fetch (url, params = {}) {
|
|
|
149
149
|
else
|
|
150
150
|
params.headers = new Headers(params.headers)
|
|
151
151
|
|
|
152
|
-
//
|
|
153
|
-
params.
|
|
152
|
+
// Sanity check inputs
|
|
153
|
+
if (params.version)
|
|
154
|
+
console.assert(Array.isArray(params.version),
|
|
155
|
+
'fetch(): `version` must be an array')
|
|
156
|
+
if (params.parents)
|
|
157
|
+
console.assert(Array.isArray(params.parents),
|
|
158
|
+
'fetch(): `parents` must be an array')
|
|
159
|
+
|
|
160
|
+
// // Always set the peer
|
|
161
|
+
// params.headers.set('peer', peer)
|
|
154
162
|
|
|
155
163
|
// We provide some shortcuts for Braid params
|
|
156
164
|
if (params.version)
|
|
157
165
|
params.headers.set('version', params.version.map(JSON.stringify).join(', '))
|
|
158
|
-
if (params.parents
|
|
166
|
+
if (params.parents)
|
|
159
167
|
params.headers.set('parents', params.parents.map(JSON.stringify).join(', '))
|
|
160
168
|
if (params.subscribe)
|
|
161
169
|
params.headers.set('subscribe', 'true')
|
|
170
|
+
if (params.peer)
|
|
171
|
+
params.header.set('peer', params.peer)
|
|
162
172
|
|
|
163
173
|
// Prevent browsers from going to disk cache
|
|
164
174
|
params.cache = 'no-cache'
|
|
@@ -342,7 +352,6 @@ async function handle_fetch_stream (stream, cb) {
|
|
|
342
352
|
// Braid-HTTP Subscription Parser
|
|
343
353
|
// ****************************
|
|
344
354
|
|
|
345
|
-
|
|
346
355
|
var subscription_parser = (cb) => ({
|
|
347
356
|
// A parser keeps some parse state
|
|
348
357
|
state: {input: ''},
|
|
@@ -359,23 +368,18 @@ var subscription_parser = (cb) => ({
|
|
|
359
368
|
|
|
360
369
|
// Now loop through the input and parse until we hit a dead end
|
|
361
370
|
while (this.state.input.trim() !== '') {
|
|
362
|
-
this.state =
|
|
371
|
+
this.state = parse_update (this.state)
|
|
363
372
|
|
|
364
373
|
// Maybe we parsed a version! That's cool!
|
|
365
374
|
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
375
|
this.cb({
|
|
374
376
|
version: this.state.version,
|
|
375
377
|
parents: this.state.parents,
|
|
376
378
|
body: this.state.body,
|
|
377
379
|
patches: this.state.patches,
|
|
378
|
-
|
|
380
|
+
|
|
381
|
+
// Output extra_headers if there are some
|
|
382
|
+
extra_headers: extra_headers(this.state.headers)
|
|
379
383
|
})
|
|
380
384
|
|
|
381
385
|
// Reset the parser for the next version!
|
|
@@ -410,7 +414,7 @@ var subscription_parser = (cb) => ({
|
|
|
410
414
|
// => {result: 'error', ...} If there is a syntax error in the input
|
|
411
415
|
|
|
412
416
|
|
|
413
|
-
function
|
|
417
|
+
function parse_update (state) {
|
|
414
418
|
// If we don't have headers yet, let's try to parse some
|
|
415
419
|
if (!state.headers) {
|
|
416
420
|
var parsed = parse_headers(state.input)
|
|
@@ -488,7 +492,8 @@ function parse_headers (input) {
|
|
|
488
492
|
// Success! Let's parse special headers
|
|
489
493
|
if ('version' in headers)
|
|
490
494
|
headers.version = JSON.parse('['+headers.version+']')
|
|
491
|
-
|
|
495
|
+
if ('parents' in headers)
|
|
496
|
+
headers.parents = JSON.parse('['+headers.parents+']')
|
|
492
497
|
if ('patches' in headers)
|
|
493
498
|
headers.patches = JSON.parse(headers.patches)
|
|
494
499
|
|
|
@@ -632,13 +637,8 @@ function parse_body (state) {
|
|
|
632
637
|
last_patch.unit = match.unit
|
|
633
638
|
last_patch.range = match.range
|
|
634
639
|
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
|
|
640
|
+
last_patch.extra_headers = extra_headers(last_patch.headers)
|
|
641
|
+
delete last_patch.headers // We only keep the extra headers ^^
|
|
642
642
|
|
|
643
643
|
// Consume the parsed input
|
|
644
644
|
state.input = state.input.substring(content_length)
|
|
@@ -655,6 +655,28 @@ function parse_body (state) {
|
|
|
655
655
|
}
|
|
656
656
|
}
|
|
657
657
|
|
|
658
|
+
// The "extra_headers" field is returned to the client on any *update* or
|
|
659
|
+
// *patch* to include any headers that we've received, but don't have braid
|
|
660
|
+
// semantics for.
|
|
661
|
+
//
|
|
662
|
+
// This function creates that hash from a headers object, by filtering out all
|
|
663
|
+
// known headers.
|
|
664
|
+
function extra_headers (headers) {
|
|
665
|
+
// Clone headers
|
|
666
|
+
var result = Object.assign({}, headers)
|
|
667
|
+
|
|
668
|
+
// Remove the non-extra parts
|
|
669
|
+
var known_headers = ['version', 'parents', 'patches',
|
|
670
|
+
'content-length', 'content-range']
|
|
671
|
+
for (var i = 0; i < known_headers.length; i++)
|
|
672
|
+
delete result[known_headers[i]]
|
|
673
|
+
|
|
674
|
+
// Return undefined if we deleted them all
|
|
675
|
+
if (Object.keys(result).length === 0)
|
|
676
|
+
return undefined
|
|
677
|
+
|
|
678
|
+
return result
|
|
679
|
+
}
|
|
658
680
|
|
|
659
681
|
// ****************************
|
|
660
682
|
// Exports
|
|
@@ -665,7 +687,7 @@ if (typeof module !== 'undefined' && module.exports)
|
|
|
665
687
|
fetch: braid_fetch,
|
|
666
688
|
http: braidify_http,
|
|
667
689
|
subscription_parser,
|
|
668
|
-
|
|
690
|
+
parse_update,
|
|
669
691
|
parse_headers,
|
|
670
692
|
parse_body
|
|
671
693
|
}
|
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,8 +48,8 @@ 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
54
|
// version: ["me"],
|
|
55
55
|
// parents: ["mom", "dad"],
|
|
@@ -57,7 +57,7 @@ fetch('https://braid.org/chat', {subscribe: true}).then(
|
|
|
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)
|
|
@@ -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
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))
|