hypercore-fetch 8.6.1 → 9.0.0

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/package.json CHANGED
@@ -1,10 +1,8 @@
1
1
  {
2
2
  "name": "hypercore-fetch",
3
- "version": "8.6.1",
3
+ "version": "9.0.0",
4
4
  "description": "Implementation of Fetch that uses the Dat SDK for loading p2p content",
5
- "bin": {
6
- "hypercore-fetch": "bin.js"
7
- },
5
+ "type": "module",
8
6
  "main": "index.js",
9
7
  "scripts": {
10
8
  "test": "node test",
@@ -25,22 +23,16 @@
25
23
  },
26
24
  "homepage": "https://github.com/RangerMauve/hypercore-fetch#readme",
27
25
  "dependencies": {
28
- "busboy": "^0.3.1",
29
26
  "event-iterator": "^2.0.0",
30
- "fetch-headers": "^2.0.0",
31
- "hyper-dns": "^0.12.0",
32
- "hyper-sdk": "^3.0.9",
33
- "make-dir": "^3.1.0",
34
- "make-fetch": "^2.3.3",
35
- "mime": "^2.4.4",
27
+ "hyperdrive": "^11.0.0-alpha.10",
28
+ "make-fetch": "^3.1.0",
29
+ "mime": "^3.0.0",
36
30
  "range-parser": "^1.2.1",
37
- "resolve-dat-path": "^2.0.0",
38
- "sodium-universal": "^3.0.2",
39
- "streamx": "^2.10.0"
31
+ "streamx": "^2.13.0"
40
32
  },
41
33
  "devDependencies": {
42
- "form-data": "^4.0.0",
43
- "random-access-memory": "^3.1.1",
34
+ "@rangermauve/fetch-event-source": "^1.0.3",
35
+ "hyper-sdk": "^4.1.1",
44
36
  "standard": "^17.0.0",
45
37
  "tape": "^5.2.2"
46
38
  }
package/test.js CHANGED
@@ -1,282 +1,387 @@
1
- const SDK = require('hyper-sdk')
2
- const test = require('tape')
3
- const FormData = require('form-data')
1
+ /* global FormData, Blob */
2
+ import * as SDK from 'hyper-sdk'
3
+ import test from 'tape'
4
+ import createEventSource from '@rangermauve/fetch-event-source'
5
+ import { once } from 'events'
4
6
 
5
- runTests()
7
+ import makeHyperFetch from './index.js'
6
8
 
7
9
  const SAMPLE_CONTENT = 'Hello World'
10
+ let count = 0
11
+ function next () {
12
+ return count++
13
+ }
8
14
 
9
- async function runTests () {
10
- const { Hyperdrive, close } = await SDK({
11
- persist: false
15
+ async function nextURL (t) {
16
+ const createResponse = await fetch(`hyper://localhost/?key=example${next()}`, {
17
+ method: 'post'
12
18
  })
19
+ await checkResponse(createResponse, t, 'Created new drive')
13
20
 
14
- const { Hyperdrive: Hyperdrive2, close: close2 } = await SDK({
15
- persist: false
16
- })
21
+ const created = await createResponse.text()
22
+ return created
23
+ }
17
24
 
18
- const fetch = require('./')({
19
- Hyperdrive,
20
- writable: true
21
- })
25
+ const sdk1 = await SDK.create({ storage: false })
26
+ const sdk2 = await SDK.create({ storage: false })
27
+
28
+ const fetch = await makeHyperFetch({
29
+ sdk: sdk1,
30
+ writable: true
31
+ })
22
32
 
23
- const fetch2 = require('./')({
24
- Hyperdrive: Hyperdrive2,
25
- writable: true
33
+ const fetch2 = await makeHyperFetch({
34
+ sdk: sdk2,
35
+ writable: true
36
+ })
37
+
38
+ test.onFinish(() => {
39
+ sdk1.close()
40
+ sdk2.close()
41
+ })
42
+
43
+ test('Quick check', async (t) => {
44
+ const createResponse = await fetch(`hyper://localhost/?key=example${next()}`, {
45
+ method: 'post'
26
46
  })
27
47
 
28
- test.onFinish(() => {
29
- close()
30
- close2()
48
+ await checkResponse(createResponse, t, 'Created new drive')
49
+
50
+ const created = await createResponse.text()
51
+
52
+ t.ok(created.startsWith('hyper://'), 'Created drive has hyper URL')
53
+
54
+ const existsResponse = await fetch(created)
55
+
56
+ await checkResponse(existsResponse, t)
57
+
58
+ t.deepEqual(await existsResponse.json(), [], 'Empty dir on create')
59
+
60
+ const uploadLocation = new URL('./example.txt', created)
61
+
62
+ const uploadResponse = await fetch(uploadLocation, {
63
+ method: 'put',
64
+ body: SAMPLE_CONTENT
31
65
  })
32
66
 
33
- test('Read index.html', async (t) => {
34
- const archive = Hyperdrive('example1')
67
+ await checkResponse(uploadResponse, t)
35
68
 
36
- const FILE_LOCATION = '/index.html'
37
- const FILE_DATA = '<h1>Hello World!</h1>'
69
+ const uploadedContentResponse = await fetch(uploadLocation)
38
70
 
39
- await archive.writeFile(FILE_LOCATION, FILE_DATA)
71
+ await checkResponse(uploadedContentResponse, t)
40
72
 
41
- const url = `hyper://${archive.key.toString('hex')}${FILE_LOCATION}`
73
+ const content = await uploadedContentResponse.text()
74
+ const contentType = uploadedContentResponse.headers.get('Content-Type')
42
75
 
43
- t.pass('Prepped archive ' + url)
76
+ t.equal(contentType, 'text/plain; charset=utf-8', 'Content got expected mime type')
77
+ t.equal(content, SAMPLE_CONTENT, 'Got uploaded content back out')
44
78
 
45
- const response = await fetch(url)
79
+ const dirResponse = await fetch2(created)
46
80
 
47
- t.pass('got response')
81
+ await checkResponse(dirResponse, t)
48
82
 
49
- const text = await response.text()
83
+ t.deepEqual(await dirResponse.json(), ['example.txt'], 'File got added')
84
+ })
50
85
 
51
- t.pass('got response text')
86
+ test('PUT file', async (t) => {
87
+ const created = await nextURL(t)
52
88
 
53
- const contentType = response.headers.get('content-type')
89
+ const uploadLocation = new URL('./example.txt', created)
54
90
 
55
- t.equal(contentType, 'text/html; charset=utf-8')
56
- t.equal(text, FILE_DATA)
57
- t.pass('Headers ' + [...response.headers.entries()])
91
+ const uploadResponse = await fetch(uploadLocation, {
92
+ method: 'put',
93
+ body: SAMPLE_CONTENT
58
94
  })
59
95
 
60
- test('GET .well-known/dat', async (t) => {
61
- const response = await fetch('hyper://example/.well-known/dat')
62
- t.ok(response, 'Got response')
63
- t.equal(response.status, 200, 'Got OK response code')
64
- const text = await response.text()
65
- t.ok(text.startsWith('dat://'), 'Returned dat URL')
66
- })
96
+ await checkResponse(uploadResponse, t, 'upload successful')
67
97
 
68
- test('GET .well-known/hyper', async (t) => {
69
- const response = await fetch('hyper://example/.well-known/hyper')
70
- t.ok(response, 'Got response')
71
- t.equal(response.status, 200, 'Got OK response code')
72
- const text = await response.text()
73
- t.ok(text.startsWith('hyper://'), 'Returned dat URL')
74
- })
98
+ const uploadedContentResponse = await fetch(uploadLocation)
75
99
 
76
- test('PUT file', async (t) => {
77
- const response1 = await fetch('hyper://example/checkthis.txt', { method: 'PUT', body: SAMPLE_CONTENT })
100
+ await checkResponse(uploadedContentResponse, t, 'able to load content')
78
101
 
79
- t.equal(response1.status, 200, 'Got OK response on write')
102
+ const content = await uploadedContentResponse.text()
103
+ const contentType = uploadedContentResponse.headers.get('Content-Type')
80
104
 
81
- const response2 = await fetch('hyper://example/checkthis.txt')
105
+ t.equal(contentType, 'text/plain; charset=utf-8', 'Content got expected mime type')
106
+ t.equal(content, SAMPLE_CONTENT, 'Got uploaded content back out')
107
+ })
108
+ test('PUT FormData', async (t) => {
109
+ const created = await nextURL(t)
82
110
 
83
- t.equal(response2.status, 200, 'Got OK response on read')
111
+ const formData = new FormData()
112
+ formData.append('file', new Blob([SAMPLE_CONTENT]), 'example.txt')
113
+ formData.append('file', new Blob([SAMPLE_CONTENT]), 'example2.txt')
84
114
 
85
- t.equal(await response2.text(), SAMPLE_CONTENT, 'Read back written data')
115
+ const uploadedResponse = await fetch(created, {
116
+ method: 'put',
117
+ body: formData
86
118
  })
87
119
 
88
- test('PUT FormData to directory', async (t) => {
89
- const form = new FormData()
90
-
91
- form.append('file', SAMPLE_CONTENT, {
92
- filename: 'example.txt'
93
- })
94
- const body = form.getBuffer()
95
- const headers = form.getHeaders()
120
+ await checkResponse(uploadedResponse, t)
96
121
 
97
- const response1 = await fetch('hyper://example/foo/bar/', {
98
- method: 'PUT',
99
- headers,
100
- body
101
- })
122
+ const file2URL = new URL('/example2.txt', created)
123
+ const file2Response = await fetch(file2URL)
102
124
 
103
- t.equal(response1.status, 200, 'Got OK response on directory upload')
125
+ await checkResponse(file2Response, t)
126
+ const file2Content = await file2Response.text()
104
127
 
105
- console.log(await response1.text())
128
+ t.equal(file2Content, SAMPLE_CONTENT, 'file contents got uploaded')
106
129
 
107
- const response2 = await fetch('hyper://example/foo/bar/example.txt')
130
+ const listDirRequest = await fetch(created)
131
+ await checkResponse(listDirRequest, t)
132
+ const entries = await listDirRequest.json()
133
+ t.deepEqual(entries, ['example.txt', 'example2.txt'], 'new files are listed')
134
+ })
135
+ test('PUT into new directory', async (t) => {
136
+ const created = await nextURL(t)
108
137
 
109
- t.equal(response2.status, 200, 'Got OK response on read')
138
+ const uploadLocation = new URL('./subfolder/example.txt', created)
110
139
 
111
- t.equal(await response2.text(), SAMPLE_CONTENT, 'Read back written data')
140
+ const uploadResponse = await fetch(uploadLocation, {
141
+ method: 'put',
142
+ body: SAMPLE_CONTENT
112
143
  })
113
144
 
114
- test('PUT file in new directory', async (t) => {
115
- const response1 = await fetch('hyper://example/fizz/buzz/example.txt', { method: 'PUT', body: SAMPLE_CONTENT })
145
+ await checkResponse(uploadResponse, t)
116
146
 
117
- t.equal(response1.status, 200, 'Got OK response on directory/file creation')
118
- })
147
+ const uploadedContentResponse = await fetch(uploadLocation)
119
148
 
120
- test('PUT to overwrite a file', async (t) => {
121
- const response1 = await fetch('hyper://example/baz/index.html', { method: 'PUT', body: SAMPLE_CONTENT })
122
- t.ok(response1.ok)
123
- const response2 = await fetch('hyper://example/baz/index.html', { method: 'PUT', body: SAMPLE_CONTENT })
149
+ await checkResponse(uploadedContentResponse, t)
124
150
 
125
- t.equal(response2.status, 200, 'Got OK response on file overwrite')
126
- })
151
+ const content = await uploadedContentResponse.text()
152
+ const contentType = uploadedContentResponse.headers.get('Content-Type')
127
153
 
128
- test('DELETE file', async (t) => {
129
- const response1 = await fetch('hyper://example/test.txt', { method: 'PUT', body: SAMPLE_CONTENT })
130
- t.ok(response1.ok)
154
+ t.equal(contentType, 'text/plain; charset=utf-8', 'Content got expected mime type')
155
+ t.equal(content, SAMPLE_CONTENT, 'Got uploaded content back out')
131
156
 
132
- const response2 = await fetch('hyper://example/test.txt', { method: 'DELETE' })
157
+ const listDirRequest = await fetch(created)
158
+ await checkResponse(listDirRequest, t)
159
+ const entries = await listDirRequest.json()
160
+ t.deepEqual(entries, ['subfolder/'], 'new files are listed')
161
+ })
162
+ test('PUT to overwrite a file', async (t) => {
163
+ const created = await nextURL(t)
133
164
 
134
- t.equal(response2.status, 200, 'Got OK response on file delete')
165
+ const uploadLocation = new URL('./example.txt', created)
135
166
 
136
- const response3 = await fetch('hyper://example/test.txt', { method: 'GET' })
167
+ const uploadResponse = await fetch(uploadLocation, {
168
+ method: 'put',
169
+ body: SAMPLE_CONTENT
170
+ })
171
+ await checkResponse(uploadResponse, t)
137
172
 
138
- t.equal(response3.status, 404, 'Got not found on deleted file')
173
+ const SHORTER_CONTENT = 'Hello'
174
+
175
+ const overWriteResponse = await fetch(uploadLocation, {
176
+ method: 'put',
177
+ body: SHORTER_CONTENT
139
178
  })
179
+ await checkResponse(overWriteResponse, t)
180
+
181
+ const uploadedContentResponse = await fetch(uploadLocation)
140
182
 
141
- test('GET index.html', async (t) => {
142
- const response1 = await fetch('hyper://example/baz')
183
+ await checkResponse(uploadedContentResponse, t)
143
184
 
144
- t.equal(await response1.text(), SAMPLE_CONTENT, 'Got index.html content')
185
+ const content = await uploadedContentResponse.text()
186
+ const contentType = uploadedContentResponse.headers.get('Content-Type')
145
187
 
146
- const response2 = await fetch('hyper://example/baz?noResolve')
188
+ t.equal(contentType, 'text/plain; charset=utf-8', 'Content got expected mime type')
189
+ t.equal(content, SHORTER_CONTENT, 'Got uploaded content back out')
190
+ })
191
+ test('DELETE a file', async (t) => {
192
+ const created = await nextURL(t)
147
193
 
148
- t.equal(response2.headers.get('content-type'), 'application/json; charset=utf-8', 'noResolve flag yields JSON by default')
149
- t.deepEqual(await response2.json(), ['index.html'], 'Listed directory')
194
+ const formData = new FormData()
195
+ formData.append('file', new Blob([SAMPLE_CONTENT]), 'example.txt')
196
+ formData.append('file', new Blob([SAMPLE_CONTENT]), 'example2.txt')
150
197
 
151
- const response3 = await fetch('hyper://example/baz?noResolve')
152
- t.equal(response3.headers.get('content-type'), 'application/json; charset=utf-8', 'noResolve flag yields JSON by default')
153
- t.deepEqual(await response3.json(), ['index.html'], 'Listed directory')
198
+ const uploadedResponse = await fetch(created, {
199
+ method: 'put',
200
+ body: formData
154
201
  })
202
+ await checkResponse(uploadedResponse, t)
155
203
 
156
- test('Create and read tags', async (t) => {
157
- await fetch('hyper://example/test.txt', { method: 'PUT', body: SAMPLE_CONTENT })
204
+ const file2URL = new URL('/example2.txt', created)
205
+ const deleteResponse = await fetch(file2URL, {
206
+ method: 'delete'
207
+ })
158
208
 
159
- const response2 = await fetch('hyper://example/$/tags/tag1', { method: 'PUT' })
160
- t.ok(response2.ok, 'Able to create tag')
209
+ await checkResponse(deleteResponse, t, 'Able to DELETE')
161
210
 
162
- const version = await response2.json()
211
+ const dirResponse = await fetch(created)
163
212
 
164
- const response3 = await fetch('hyper://example/$/tags/')
213
+ await checkResponse(dirResponse, t)
165
214
 
166
- t.ok(response3.ok, 'Able to ask for tags')
167
- t.deepEqual(await response3.json(), { tag1: version }, 'Tag got created')
215
+ t.deepEqual(await dirResponse.json(), ['example.txt'], 'Only one file remains')
216
+ })
217
+ test('DELETE a directory', async (t) => {
218
+ const created = await nextURL(t)
168
219
 
169
- // Insert a file which won't be available with the old tag
170
- await fetch('hyper://example/notaccessible.txt', { method: 'PUT', body: 'test' })
220
+ const uploadLocation = new URL('./subfolder/example.txt', created)
171
221
 
172
- const response4 = await fetch('hyper://example+tag1/notaccessible.txt')
222
+ const uploadResponse = await fetch(uploadLocation, {
223
+ method: 'put',
224
+ body: SAMPLE_CONTENT
225
+ })
226
+ await checkResponse(uploadResponse, t)
173
227
 
174
- t.equal(response4.status, 404, 'Newer file not found in older tag')
228
+ const deleteResponse = await fetch(created, {
229
+ method: 'delete'
230
+ })
231
+ await checkResponse(deleteResponse, t, 'Able to DELETE')
232
+
233
+ const listDirRequest = await fetch(created)
234
+ await checkResponse(listDirRequest, t)
235
+ const entries = await listDirRequest.json()
236
+ t.deepEqual(entries, [], 'subfolder got deleted')
237
+ })
238
+ test('Read index.html', async (t) => {
239
+ const created = await nextURL(t)
240
+ const uploadLocation = new URL('./index.html', created)
241
+
242
+ const uploadResponse = await fetch(uploadLocation, {
243
+ method: 'put',
244
+ body: SAMPLE_CONTENT
245
+ })
246
+ await checkResponse(uploadResponse, t)
175
247
 
176
- const response5 = await fetch('hyper://example/$/tags/tag1', { method: 'DELETE' })
248
+ const uploadedContentResponse = await fetch(uploadLocation)
177
249
 
178
- t.ok(response5.ok, 'Able to delete tag')
250
+ await checkResponse(uploadedContentResponse, t)
179
251
 
180
- const response6 = await fetch('hyper://example/$/tags/')
252
+ const content = await uploadedContentResponse.text()
253
+ const contentType = uploadedContentResponse.headers.get('Content-Type')
181
254
 
182
- t.deepEqual(await response6.json(), {}, 'No tags left after delete')
255
+ t.equal(contentType, 'text/html; charset=utf-8', 'got HTML mime type')
256
+ t.equal(content, SAMPLE_CONTENT, 'loaded index.html content')
257
+ })
258
+ test('Ignore index.html with noResolve', async (t) => {
259
+ const created = await nextURL(t)
260
+ const uploadLocation = new URL('./index.html', created)
261
+
262
+ const uploadResponse = await fetch(uploadLocation, {
263
+ method: 'put',
264
+ body: SAMPLE_CONTENT
183
265
  })
266
+ await checkResponse(uploadResponse, t)
184
267
 
185
- test('Load Mauve\'s blog', async (t) => {
186
- const response = await fetch('hyper://blog.mauve.moe/')
268
+ const noResolve = created + '?noResolve'
187
269
 
188
- t.ok(response.ok, 'Succesfully loaded homepage')
189
- })
270
+ const listDirRequest = await fetch(noResolve)
271
+ await checkResponse(listDirRequest, t)
272
+ const entries = await listDirRequest.json()
273
+ t.deepEqual(entries, ['index.html'], 'able to list index.html')
274
+ })
275
+ test('Read directory as HTML', async (t) => {
276
+ const created = await nextURL(t)
190
277
 
191
- test('Watch for changes', async (t) => {
192
- const response = await fetch('hyper://example/', {
193
- headers: {
194
- Accept: 'text/event-stream'
195
- }
196
- })
278
+ const formData = new FormData()
279
+ formData.append('file', new Blob([SAMPLE_CONTENT]), 'example.txt')
280
+ formData.append('file', new Blob([SAMPLE_CONTENT]), 'example2.txt')
281
+
282
+ const uploadedResponse = await fetch(created, {
283
+ method: 'put',
284
+ body: formData
285
+ })
286
+ await checkResponse(uploadedResponse, t)
197
287
 
198
- t.ok(response.ok, 'Able to open request')
199
- t.equal(response.headers.get('Content-Type'), 'text/event-stream', 'Response is event stream')
288
+ const listDirRequest = await fetch(created, {
289
+ headers: {
290
+ Accept: 'text/html'
291
+ }
292
+ })
293
+ await checkResponse(listDirRequest, t, 'Able to list HTML')
200
294
 
201
- const reader = await response.body.getReader()
295
+ const html = await listDirRequest.text()
202
296
 
203
- const [data] = await Promise.all([
204
- reader.read(),
205
- fetch('hyper://example/example4.txt', { method: 'PUT', body: 'Hello World' })
206
- ])
297
+ t.equal(listDirRequest.headers.get('Content-Type'), 'text/html; charset=utf-8', 'Returned HTML in mime type')
298
+ t.ok(html.includes('<title'), 'Listing has title')
299
+ t.ok(html.includes('./example.txt'), 'Listing has link to file')
300
+ })
301
+ test('Resolve pretty markdown URLs', async (t) => {
302
+ const created = await nextURL(t)
207
303
 
208
- t.ok(data.value, 'Got eventsource data after writing')
209
- t.ok(data.value.includes('event:change'), 'Eventsource data represents a change event')
210
- t.ok(data.value.endsWith('\n\n'), 'Ends with two newlines')
304
+ const uploadLocation = new URL('./example.md', created)
211
305
 
212
- await reader.cancel()
306
+ const uploadResponse = await fetch(uploadLocation, {
307
+ method: 'put',
308
+ body: SAMPLE_CONTENT
213
309
  })
310
+ await checkResponse(uploadResponse, t)
214
311
 
215
- test('Send extension from one peer to another', async (t) => {
216
- const domainResponse = await fetch('hyper://example/.well-known/hyper')
217
- const domain = (await domainResponse.text()).split('\n')[0]
312
+ const resolvedLocation = new URL('/example', created)
218
313
 
219
- const extensionURL = `${domain}/$/extensions/example`
220
- const extensionListURL = `${domain}/$/extensions/`
314
+ const uploadedContentResponse = await fetch(resolvedLocation)
221
315
 
222
- // Load up extension message on peer 1
223
- await fetch(extensionURL)
224
- // Load up extension message on peer 2
225
- await fetch2(extensionURL)
316
+ await checkResponse(uploadedContentResponse, t, 'able to load content')
226
317
 
227
- t.pass('Able to initialize extensions')
318
+ const content = await uploadedContentResponse.text()
319
+ const contentType = uploadedContentResponse.headers.get('Content-Type')
228
320
 
229
- const extensionListRequest = await fetch(extensionListURL)
230
- const extensionList = await extensionListRequest.json()
321
+ t.equal(content, SAMPLE_CONTENT, 'Got original content out')
322
+ t.equal(contentType, 'text/markdown; charset=utf-8', 'Got markdown mime type')
323
+ })
231
324
 
232
- // Extension list will always be alphabetically sorted
233
- t.deepEqual(extensionList, ['example', 'hypertrie'], 'Got expected list of extensions')
325
+ test('EventSource extension messages', async (t) => {
326
+ const domain = await nextURL(t)
234
327
 
235
- // Wait a bit for them to connect
236
- // TODO: Peers API
237
- await delay(2000)
328
+ const extensionURL = `${domain}$/extensions/example`
329
+ const extensionListURL = `${domain}$/extensions/`
238
330
 
239
- const peerResponse1 = await fetch(extensionURL)
240
- const peerList1 = await peerResponse1.json()
331
+ // Load up extension message on peer 1
332
+ const extensionLoadResponse1 = await fetch(extensionURL)
333
+ await checkResponse(extensionLoadResponse1, t)
334
+ // Load up extension message on peer 2
335
+ const extensionLoadResponse2 = await fetch2(extensionURL)
336
+ await checkResponse(extensionLoadResponse2, t)
241
337
 
242
- t.equal(peerList1.length, 1, 'Got one peer for extension message on peer1')
338
+ const extensionListRequest = await fetch(extensionListURL)
339
+ const extensionList = await extensionListRequest.json()
243
340
 
244
- const peerResponse2 = await fetch2(extensionURL)
245
- const peerList2 = await peerResponse2.json()
341
+ // Extension list will always be alphabetically sorted
342
+ t.deepEqual(extensionList, ['example'], 'Got expected list of extensions')
246
343
 
247
- t.equal(peerList2.length, 1, 'Got one peer for extension message on peer2')
344
+ const peerResponse1 = await fetch(extensionURL)
345
+ const peerList1 = await peerResponse1.json()
248
346
 
249
- const eventRequest = await fetch(extensionListURL, {
250
- headers: {
251
- Accept: 'text/event-stream'
252
- }
253
- })
347
+ t.equal(peerList1.length, 1, 'Got one peer for extension message on peer1')
254
348
 
255
- t.ok(eventRequest.ok, 'Able to open request')
256
- t.equal(eventRequest.headers.get('Content-Type'), 'text/event-stream', 'Response is event stream')
349
+ const peerResponse2 = await fetch2(extensionURL)
350
+ const peerList2 = await peerResponse2.json()
257
351
 
258
- const reader = await eventRequest.body.getReader()
352
+ t.equal(peerList2.length, 1, 'Got one peer for extension message on peer2')
259
353
 
260
- const toRead = reader.read()
354
+ const { EventSource } = createEventSource(fetch)
355
+ const source = new EventSource(extensionListURL)
261
356
 
262
- await delay(500)
357
+ await Promise.race([
358
+ once(source, 'open'),
359
+ once(source, 'error').then(([e]) => { throw e })
360
+ ])
263
361
 
264
- const broadcastRequest = await fetch2(extensionURL, { method: 'POST', body: 'Hello World' })
362
+ const toRead = Promise.race([
363
+ once(source, 'example'),
364
+ once(source, 'error').then(([e]) => { throw e })
365
+ ])
265
366
 
266
- t.ok(broadcastRequest.ok, 'Able to broadcast to peers')
367
+ const broadcastRequest = await fetch2(extensionURL, { method: 'POST', body: SAMPLE_CONTENT })
267
368
 
268
- const data = await toRead
369
+ t.ok(broadcastRequest.ok, 'Able to broadcast to peers')
269
370
 
270
- t.ok(data.value, 'Got eventsource data after writing')
271
- t.ok(data.value.includes('event:example\n'), 'EventSource data represents an example event')
272
- t.ok(data.value.includes('data:Hello World\n'), 'EventSource data contains expected body')
273
- t.ok(data.value.includes('id:'), 'EventSource data contains an ID')
274
- t.ok(data.value.endsWith('\n\n'), 'Ends with two newlines')
371
+ const [event] = await toRead
275
372
 
276
- await reader.cancel()
277
- })
278
- }
373
+ const { type, data, lastEventId } = event
374
+
375
+ t.equal(data, SAMPLE_CONTENT, 'Got data from event')
376
+ t.equal(type, 'example', 'Event got set to extension message name')
377
+ t.ok(lastEventId, 'Event contained peer ID')
378
+ })
279
379
 
280
- function delay (time) {
281
- return new Promise((resolve) => setTimeout(resolve, time))
380
+ async function checkResponse (response, t, successMessage = 'Response OK') {
381
+ if (!response.ok) {
382
+ const message = await response.text()
383
+ t.fail(new Error(`HTTP Error ${response.status}:\n${message}`))
384
+ } else {
385
+ t.pass(successMessage)
386
+ }
282
387
  }
package/bin.js DELETED
@@ -1,27 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const eosp = require('end-of-stream-promise')
4
- const { Readable } = require('streamx')
5
-
6
- run()
7
- .catch((e) => process.nextTick(() => {
8
- throw e
9
- }))
10
-
11
- async function run () {
12
- const fetch = require('./')()
13
-
14
- try {
15
- const url = process.argv[2]
16
-
17
- const response = await fetch(url)
18
-
19
- const stream = Readable.from(response.body)
20
-
21
- stream.pipe(process.stdout)
22
-
23
- await eosp(stream)
24
- } finally {
25
- fetch.close()
26
- }
27
- }