braid-http 1.3.106 → 1.3.107
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/README.md +48 -32
- package/braid-http-client.js +32 -8
- package/braid-http-server.js +20 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -82,7 +82,39 @@ fetch('https://braid.org/chat', {subscribe: true}).then(
|
|
|
82
82
|
)
|
|
83
83
|
```
|
|
84
84
|
|
|
85
|
-
|
|
85
|
+
### Example Subscription with Async/Await
|
|
86
|
+
|
|
87
|
+
```javascript
|
|
88
|
+
(await fetch('/chat', {subscribe: true, retry: true})).subscribe(
|
|
89
|
+
(update) => {
|
|
90
|
+
// We got a new update!
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Example Subscription with `for await`
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
var subscription_iterator = (await fetch('/chat',
|
|
98
|
+
{subscribe: true, retry: true})).subscription
|
|
99
|
+
for await (var update of subscription_iterator) {
|
|
100
|
+
// Updates might come in the form of patches:
|
|
101
|
+
if (update.patches)
|
|
102
|
+
chat = apply_patches(update.patches, chat)
|
|
103
|
+
|
|
104
|
+
// Or complete snapshots:
|
|
105
|
+
else
|
|
106
|
+
// Beware the server doesn't send these yet.
|
|
107
|
+
chat = JSON.parse(update.body_text)
|
|
108
|
+
|
|
109
|
+
render_stuff()
|
|
110
|
+
}
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Advanced client features
|
|
114
|
+
|
|
115
|
+
#### Automatic reconection
|
|
116
|
+
|
|
117
|
+
Pass a `{retry: true}` option to `fetch()` to automatically reconnect:
|
|
86
118
|
|
|
87
119
|
```javascript
|
|
88
120
|
fetch('https://braid.org/chat', {subscribe: true, retry: true}).then(
|
|
@@ -95,12 +127,16 @@ fetch('https://braid.org/chat', {subscribe: true, retry: true}).then(
|
|
|
95
127
|
)
|
|
96
128
|
```
|
|
97
129
|
|
|
98
|
-
|
|
130
|
+
|
|
131
|
+
To update the parent version that you reconnect from, set the `parents`
|
|
132
|
+
paramter to a function rather than an array of strings:
|
|
99
133
|
|
|
100
134
|
```javascript
|
|
101
|
-
fetch('https://braid.org/chat', {
|
|
102
|
-
|
|
103
|
-
|
|
135
|
+
fetch('https://braid.org/chat', {
|
|
136
|
+
subscribe: true,
|
|
137
|
+
retry: true,
|
|
138
|
+
parents: () => current_parents
|
|
139
|
+
}).then(
|
|
104
140
|
res => res.subscribe(
|
|
105
141
|
(update) => {
|
|
106
142
|
console.log('We got a new update!', update)
|
|
@@ -110,7 +146,13 @@ fetch('https://braid.org/chat', {subscribe: true, retry: true, parents: () => {
|
|
|
110
146
|
)
|
|
111
147
|
```
|
|
112
148
|
|
|
113
|
-
|
|
149
|
+
It will call the `parents` function each time it reconnects to learn the
|
|
150
|
+
current parents to connection from.
|
|
151
|
+
|
|
152
|
+
#### Monitor the connection status
|
|
153
|
+
|
|
154
|
+
The `onSubscriptionStatus(status)` callback informs you when the connection
|
|
155
|
+
goes online and offline:
|
|
114
156
|
|
|
115
157
|
```javascript
|
|
116
158
|
fetch('https://braid.org/chat', {
|
|
@@ -133,33 +175,7 @@ The callback receives an object with only the fields relevant to the event:
|
|
|
133
175
|
- `{online: true}` — the subscription is connected
|
|
134
176
|
- `{online: false, error}` — the subscription went offline, with the error/reason for disconnection
|
|
135
177
|
|
|
136
|
-
### Example Subscription with Async/Await
|
|
137
|
-
|
|
138
|
-
```javascript
|
|
139
|
-
(await fetch('/chat', {subscribe: true, retry: true})).subscribe(
|
|
140
|
-
(update) => {
|
|
141
|
-
// We got a new update!
|
|
142
|
-
})
|
|
143
|
-
```
|
|
144
|
-
|
|
145
|
-
### Example Subscription with `for await`
|
|
146
178
|
|
|
147
|
-
```javascript
|
|
148
|
-
var subscription_iterator = (await fetch('/chat',
|
|
149
|
-
{subscribe: true, retry: true})).subscription
|
|
150
|
-
for await (var update of subscription_iterator) {
|
|
151
|
-
// Updates might come in the form of patches:
|
|
152
|
-
if (update.patches)
|
|
153
|
-
chat = apply_patches(update.patches, chat)
|
|
154
|
-
|
|
155
|
-
// Or complete snapshots:
|
|
156
|
-
else
|
|
157
|
-
// Beware the server doesn't send these yet.
|
|
158
|
-
chat = JSON.parse(update.body_text)
|
|
159
|
-
|
|
160
|
-
render_stuff()
|
|
161
|
-
}
|
|
162
|
-
```
|
|
163
179
|
|
|
164
180
|
## Using it in Nodejs
|
|
165
181
|
|
package/braid-http-client.js
CHANGED
|
@@ -159,20 +159,21 @@ async function braid_fetch (url, params = {}) {
|
|
|
159
159
|
params.headers.set('version', params.version.map(JSON.stringify).map(ascii_ify).join(', '))
|
|
160
160
|
if (Array.isArray(params.parents))
|
|
161
161
|
params.headers.set('parents', params.parents.map(JSON.stringify).map(ascii_ify).join(', '))
|
|
162
|
-
if (params.subscribe)
|
|
162
|
+
if (params.subscribe) {
|
|
163
163
|
params.headers.set('subscribe', 'true')
|
|
164
|
+
// Prevent this response from being cached
|
|
165
|
+
params.cache = 'no-store'
|
|
166
|
+
}
|
|
167
|
+
|
|
164
168
|
if (params.peer)
|
|
165
169
|
params.headers.set('peer', params.peer)
|
|
166
|
-
|
|
170
|
+
|
|
167
171
|
if (params.heartbeats)
|
|
168
172
|
params.headers.set('heartbeats',
|
|
169
173
|
typeof params.heartbeats === 'number'
|
|
170
174
|
? `${params.heartbeats}s`
|
|
171
175
|
: params.heartbeats)
|
|
172
176
|
|
|
173
|
-
// Prevent browsers from going to disk cache
|
|
174
|
-
params.cache = 'no-cache'
|
|
175
|
-
|
|
176
177
|
// Prepare patches
|
|
177
178
|
if (params.patches) {
|
|
178
179
|
console.assert(!params.body, 'Cannot send both patches and body')
|
|
@@ -311,9 +312,32 @@ async function braid_fetch (url, params = {}) {
|
|
|
311
312
|
if (parents) params.headers.set('parents', parents.map(JSON.stringify).join(', '))
|
|
312
313
|
}
|
|
313
314
|
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
315
|
+
// Work around Chrome bug where when you restore a closed tab,
|
|
316
|
+
// Chrome overrides our {cache:'no-store'} parameter and instead sets
|
|
317
|
+
// SKIP_CACHE_VALIDATION, which overrides our subscription response
|
|
318
|
+
// with ... a static entry from its cache! That sucks.
|
|
319
|
+
//
|
|
320
|
+
// See https://issues.chromium.org/issues/490673934
|
|
321
|
+
//
|
|
322
|
+
// Our workaround is to detect if we are in chrome, and subscribing,
|
|
323
|
+
// and are within a page restoration... and then...
|
|
324
|
+
if (!is_nodejs && params.headers.has('subscribe')) {
|
|
325
|
+
var nav_entry = performance?.getEntriesByType?.('navigation')?.[0]
|
|
326
|
+
if (nav_entry?.type === 'back_forward'
|
|
327
|
+
&& document.readyState !== 'complete')
|
|
328
|
+
|
|
329
|
+
// ...we just wait until the page has loaded to send this fetch
|
|
330
|
+
await new Promise(r => window.addEventListener('load', r))
|
|
331
|
+
|
|
332
|
+
// Because the SKIP_CACHE_VALIDATION policy in chrome goes away
|
|
333
|
+
// as soon as the page loads.
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Braid-Chrome needs the following special (undocumented)
|
|
337
|
+
// `onFetch` feature. It's a callback with the params as they
|
|
338
|
+
// are being sent to the underlying fetch(). The Braid
|
|
339
|
+
// devtools wants to be able to display these in its devtools
|
|
340
|
+
// panel.
|
|
317
341
|
params.onFetch?.(url, params, underlying_aborter)
|
|
318
342
|
|
|
319
343
|
// Now we run the original fetch....
|
package/braid-http-server.js
CHANGED
|
@@ -332,12 +332,22 @@ function braidify (req, res, next) {
|
|
|
332
332
|
if ((subscribe === '' || subscribe)
|
|
333
333
|
// And this is a GET, because `Subscribe:` is only
|
|
334
334
|
// specified for GET thus far...
|
|
335
|
-
&& req.method === 'GET')
|
|
335
|
+
&& req.method === 'GET') {
|
|
336
336
|
// Then let's set 'subscribe' on. We default to "true", but if the
|
|
337
337
|
// client actually specified a value other than empty string '', let's
|
|
338
338
|
// use that rich value.
|
|
339
339
|
subscribe = subscribe || true
|
|
340
340
|
|
|
341
|
+
// Great. Now we also need to set the response body's content-type, so
|
|
342
|
+
// that FireFox doesn't try to sniff the content-type on a stream and
|
|
343
|
+
// hang forever waiting for 512 bytes (see firefox issue
|
|
344
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1544313)
|
|
345
|
+
res.setHeader('Content-Type', 'message/http-sequence')
|
|
346
|
+
|
|
347
|
+
// And we don't want any caches trying to store these stream bodies.
|
|
348
|
+
res.setHeader('Cache-Control', 'no-store')
|
|
349
|
+
}
|
|
350
|
+
|
|
341
351
|
// Define convenience variables
|
|
342
352
|
req.version = version
|
|
343
353
|
req.parents = parents
|
|
@@ -848,10 +858,15 @@ async function send_update(res, data, url, peer) {
|
|
|
848
858
|
// See also https://github.com/braid-org/braid-spec/issues/73
|
|
849
859
|
if (res.isSubscription) {
|
|
850
860
|
var extra_newlines = 1
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
861
|
+
|
|
862
|
+
// Note: this firefox workaround was replaced with a content-type fix
|
|
863
|
+
// above. We realized that content-type fixes the issue when we found
|
|
864
|
+
// https://bugzilla.mozilla.org/show_bug.cgi?id=1544313
|
|
865
|
+
//
|
|
866
|
+
// if (res.is_firefox)
|
|
867
|
+
// // Work around Firefox network buffering bug
|
|
868
|
+
// // See https://github.com/braid-org/braidjs/issues/15
|
|
869
|
+
// extra_newlines = 240
|
|
855
870
|
|
|
856
871
|
for (var i = 0; i < 1 + extra_newlines; i++)
|
|
857
872
|
res.write("\r\n")
|