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.
@@ -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('version', ...) feature
50
+ // Wrap the callback to provide our new .on('update', ...) feature
52
51
  // on nodejs servers
53
- var on_version,
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('version', cb)
61
- if (key === 'version') {
59
+ // Define .on('update', cb)
60
+ if (key === 'update'
61
+ || key === 'version' /* Deprecated API calls it 'version' */ ) {
62
62
 
63
- // If we have an 'version' handler, let's remember it
64
- on_version = f
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((version, error) => {
67
+ var parser = subscription_parser((update, error) => {
68
68
  if (!error)
69
- on_version && on_version(version)
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
- // Always set the peer
153
- params.headers.set('peer', peer)
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?.length)
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 = parse_version (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
- ...((x => Object.keys(x).length ? {extra_headers: x} : {})(Object.fromEntries(Object.entries(this.state.headers).filter(([k, v]) => !ignore_headers[k]))))
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 parse_version (state) {
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
- headers.parents = JSON.parse('['+(headers.parents ?? '')+']')
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
- // instead of headers, we'll create an "extra_headers" field that ignore the headers we've used
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
- parse_version,
690
+ parse_update,
669
691
  parse_headers,
670
692
  parse_body
671
693
  }
@@ -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('['+(req.headers.version ?? '')+']'),
199
- parents = JSON.parse('['+(req.headers.parents ?? '')+']'),
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.sendVersion = (stuff) => send_version(res, stuff, req.url, peer)
215
- res.sendUpdate = res.sendVersion
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 send_version(res, data, url, peer) {
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "braid-http",
3
- "version": "0.3.2",
3
+ "version": "0.3.4",
4
4
  "description": "An implementation of Braid-HTTP for Node.js and Browsers",
5
5
  "scripts": {
6
6
  "test": "node test/server.js"
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( new_version => ... )`
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
- (new_version) => {
52
- console.log('We got a new version!', new_version)
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 new_version will contain either patches *or* body
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
- (new_version) => {
73
- console.log('We got a new version!', new_version)
74
- // Do something with the new_version
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
- (new_version) => {
90
- // We got a new version!
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 versions:
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('version', (version) => {
221
- console.log('well we got one', version)
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('version', (version) => {
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
- // // Version will contain either patches *or* body, but not both
243
- console.log('We got a new version!', version)
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))