hypercore-fetch 8.6.0 → 8.6.2-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/.github/workflows/test.yml +22 -0
- package/LICENSE +0 -0
- package/README.md +67 -116
- package/index.js +482 -670
- package/package.json +11 -18
- package/test.js +245 -186
- package/bin.js +0 -27
package/package.json
CHANGED
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore-fetch",
|
|
3
|
-
"version": "8.6.0",
|
|
3
|
+
"version": "8.6.2-0",
|
|
4
4
|
"description": "Implementation of Fetch that uses the Dat SDK for loading p2p content",
|
|
5
|
-
"
|
|
6
|
-
"hypercore-fetch": "bin.js"
|
|
7
|
-
},
|
|
8
|
-
"main": "index.js",
|
|
5
|
+
"type": "module",
|
|
9
6
|
"scripts": {
|
|
10
|
-
"test": "node test"
|
|
7
|
+
"test": "node test",
|
|
8
|
+
"lint": "standard --fix"
|
|
11
9
|
},
|
|
12
10
|
"repository": {
|
|
13
11
|
"type": "git",
|
|
@@ -24,22 +22,17 @@
|
|
|
24
22
|
},
|
|
25
23
|
"homepage": "https://github.com/RangerMauve/hypercore-fetch#readme",
|
|
26
24
|
"dependencies": {
|
|
27
|
-
"busboy": "^0.3.1",
|
|
28
25
|
"event-iterator": "^2.0.0",
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"make-dir": "^3.1.0",
|
|
33
|
-
"make-fetch": "^2.2.1",
|
|
34
|
-
"mime": "^2.4.4",
|
|
26
|
+
"hyperdrive": "^11.0.0-alpha.10",
|
|
27
|
+
"make-fetch": "^3.1.0",
|
|
28
|
+
"mime": "^3.0.0",
|
|
35
29
|
"range-parser": "^1.2.1",
|
|
36
|
-
"
|
|
37
|
-
"sodium-universal": "^3.0.2",
|
|
38
|
-
"streamx": "^2.10.0"
|
|
30
|
+
"streamx": "^2.13.0"
|
|
39
31
|
},
|
|
40
32
|
"devDependencies": {
|
|
41
|
-
"
|
|
42
|
-
"
|
|
33
|
+
"@rangermauve/fetch-event-source": "^1.0.3",
|
|
34
|
+
"hyper-sdk": "^4.1.0",
|
|
35
|
+
"standard": "^17.0.0",
|
|
43
36
|
"tape": "^5.2.2"
|
|
44
37
|
}
|
|
45
38
|
}
|
package/test.js
CHANGED
|
@@ -1,282 +1,341 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
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
|
-
|
|
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
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
const { Hyperdrive: Hyperdrive2, close: close2 } = await SDK({
|
|
15
|
-
persist: false
|
|
15
|
+
async function nextURL (t) {
|
|
16
|
+
const createResponse = await fetch(`hyper://localhost/?key=example${next()}`, {
|
|
17
|
+
method: 'post'
|
|
16
18
|
})
|
|
19
|
+
await checkResponse(createResponse, t, 'Created new drive')
|
|
17
20
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
})
|
|
21
|
+
const created = await createResponse.text()
|
|
22
|
+
return created
|
|
23
|
+
}
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
writable: true
|
|
26
|
-
})
|
|
25
|
+
const sdk1 = await SDK.create({ storage: false })
|
|
26
|
+
const sdk2 = await SDK.create({ storage: false })
|
|
27
27
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
const fetch = await makeHyperFetch({
|
|
29
|
+
sdk: sdk1,
|
|
30
|
+
writable: true
|
|
31
|
+
})
|
|
32
32
|
|
|
33
|
-
|
|
34
|
-
|
|
33
|
+
const fetch2 = await makeHyperFetch({
|
|
34
|
+
sdk: sdk2,
|
|
35
|
+
writable: true
|
|
36
|
+
})
|
|
35
37
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
test.onFinish(() => {
|
|
39
|
+
sdk1.close()
|
|
40
|
+
sdk2.close()
|
|
41
|
+
})
|
|
38
42
|
|
|
39
|
-
|
|
43
|
+
test('Quick check', async (t) => {
|
|
44
|
+
const createResponse = await fetch(`hyper://localhost/?key=example${next()}`, {
|
|
45
|
+
method: 'post'
|
|
46
|
+
})
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
await checkResponse(createResponse, t, 'Created new drive')
|
|
42
49
|
|
|
43
|
-
|
|
50
|
+
const created = await createResponse.text()
|
|
44
51
|
|
|
45
|
-
|
|
52
|
+
t.ok(created.startsWith('hyper://'), 'Created drive has hyper URL')
|
|
46
53
|
|
|
47
|
-
|
|
54
|
+
const existsResponse = await fetch(created)
|
|
48
55
|
|
|
49
|
-
|
|
56
|
+
await checkResponse(existsResponse, t)
|
|
50
57
|
|
|
51
|
-
|
|
58
|
+
t.deepEqual(await existsResponse.json(), [], 'Empty dir on create')
|
|
52
59
|
|
|
53
|
-
|
|
60
|
+
const uploadLocation = new URL('./example.txt', created)
|
|
54
61
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
const uploadResponse = await fetch(uploadLocation, {
|
|
63
|
+
method: 'put',
|
|
64
|
+
body: SAMPLE_CONTENT
|
|
58
65
|
})
|
|
59
66
|
|
|
60
|
-
|
|
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
|
-
})
|
|
67
|
+
await checkResponse(uploadResponse, t)
|
|
67
68
|
|
|
68
|
-
|
|
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
|
-
})
|
|
69
|
+
const uploadedContentResponse = await fetch(uploadLocation)
|
|
75
70
|
|
|
76
|
-
|
|
77
|
-
const response1 = await fetch('hyper://example/checkthis.txt', { method: 'PUT', body: SAMPLE_CONTENT })
|
|
71
|
+
await checkResponse(uploadedContentResponse, t)
|
|
78
72
|
|
|
79
|
-
|
|
73
|
+
const content = await uploadedContentResponse.text()
|
|
74
|
+
const contentType = uploadedContentResponse.headers.get('Content-Type')
|
|
80
75
|
|
|
81
|
-
|
|
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')
|
|
82
78
|
|
|
83
|
-
|
|
79
|
+
const dirResponse = await fetch2(created)
|
|
84
80
|
|
|
85
|
-
|
|
86
|
-
})
|
|
81
|
+
await checkResponse(dirResponse, t)
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
83
|
+
t.deepEqual(await dirResponse.json(), ['example.txt'], 'File got added')
|
|
84
|
+
})
|
|
90
85
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
})
|
|
94
|
-
const body = form.getBuffer()
|
|
95
|
-
const headers = form.getHeaders()
|
|
86
|
+
test('PUT file', async (t) => {
|
|
87
|
+
const created = await nextURL(t)
|
|
96
88
|
|
|
97
|
-
|
|
98
|
-
method: 'PUT',
|
|
99
|
-
headers,
|
|
100
|
-
body
|
|
101
|
-
})
|
|
89
|
+
const uploadLocation = new URL('./example.txt', created)
|
|
102
90
|
|
|
103
|
-
|
|
91
|
+
const uploadResponse = await fetch(uploadLocation, {
|
|
92
|
+
method: 'put',
|
|
93
|
+
body: SAMPLE_CONTENT
|
|
94
|
+
})
|
|
104
95
|
|
|
105
|
-
|
|
96
|
+
await checkResponse(uploadResponse, t)
|
|
106
97
|
|
|
107
|
-
|
|
98
|
+
const uploadedContentResponse = await fetch(uploadLocation)
|
|
108
99
|
|
|
109
|
-
|
|
100
|
+
await checkResponse(uploadedContentResponse, t)
|
|
110
101
|
|
|
111
|
-
|
|
112
|
-
|
|
102
|
+
const content = await uploadedContentResponse.text()
|
|
103
|
+
const contentType = uploadedContentResponse.headers.get('Content-Type')
|
|
104
|
+
|
|
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)
|
|
113
110
|
|
|
114
|
-
|
|
115
|
-
|
|
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')
|
|
116
114
|
|
|
117
|
-
|
|
115
|
+
const uploadedResponse = await fetch(created, {
|
|
116
|
+
method: 'put',
|
|
117
|
+
body: formData
|
|
118
118
|
})
|
|
119
119
|
|
|
120
|
-
|
|
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 })
|
|
120
|
+
await checkResponse(uploadedResponse, t)
|
|
124
121
|
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
const file2URL = new URL('/example2.txt', created)
|
|
123
|
+
const file2Response = await fetch(file2URL)
|
|
127
124
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
t.ok(response1.ok)
|
|
125
|
+
await checkResponse(file2Response, t)
|
|
126
|
+
const file2Content = await file2Response.text()
|
|
131
127
|
|
|
132
|
-
|
|
128
|
+
t.equal(file2Content, SAMPLE_CONTENT, 'file contents got uploaded')
|
|
133
129
|
|
|
134
|
-
|
|
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)
|
|
135
137
|
|
|
136
|
-
|
|
138
|
+
const uploadLocation = new URL('./subfolder/example.txt', created)
|
|
137
139
|
|
|
138
|
-
|
|
140
|
+
const uploadResponse = await fetch(uploadLocation, {
|
|
141
|
+
method: 'put',
|
|
142
|
+
body: SAMPLE_CONTENT
|
|
139
143
|
})
|
|
140
144
|
|
|
141
|
-
|
|
142
|
-
const response1 = await fetch('hyper://example/baz')
|
|
145
|
+
await checkResponse(uploadResponse, t)
|
|
143
146
|
|
|
144
|
-
|
|
147
|
+
const uploadedContentResponse = await fetch(uploadLocation)
|
|
145
148
|
|
|
146
|
-
|
|
149
|
+
await checkResponse(uploadedContentResponse, t)
|
|
147
150
|
|
|
148
|
-
|
|
149
|
-
|
|
151
|
+
const content = await uploadedContentResponse.text()
|
|
152
|
+
const contentType = uploadedContentResponse.headers.get('Content-Type')
|
|
150
153
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
t.deepEqual(await response3.json(), ['index.html'], 'Listed directory')
|
|
154
|
-
})
|
|
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')
|
|
155
156
|
|
|
156
|
-
|
|
157
|
-
|
|
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)
|
|
158
164
|
|
|
159
|
-
|
|
160
|
-
t.ok(response2.ok, 'Able to create tag')
|
|
165
|
+
const uploadLocation = new URL('./example.txt', created)
|
|
161
166
|
|
|
162
|
-
|
|
167
|
+
const uploadResponse = await fetch(uploadLocation, {
|
|
168
|
+
method: 'put',
|
|
169
|
+
body: SAMPLE_CONTENT
|
|
170
|
+
})
|
|
171
|
+
await checkResponse(uploadResponse, t)
|
|
163
172
|
|
|
164
|
-
|
|
173
|
+
const SHORTER_CONTENT = 'Hello'
|
|
165
174
|
|
|
166
|
-
|
|
167
|
-
|
|
175
|
+
const overWriteResponse = await fetch(uploadLocation, {
|
|
176
|
+
method: 'put',
|
|
177
|
+
body: SHORTER_CONTENT
|
|
178
|
+
})
|
|
179
|
+
await checkResponse(overWriteResponse, t)
|
|
168
180
|
|
|
169
|
-
|
|
170
|
-
await fetch('hyper://example/notaccessible.txt', { method: 'PUT', body: 'test' })
|
|
181
|
+
const uploadedContentResponse = await fetch(uploadLocation)
|
|
171
182
|
|
|
172
|
-
|
|
183
|
+
await checkResponse(uploadedContentResponse, t)
|
|
173
184
|
|
|
174
|
-
|
|
185
|
+
const content = await uploadedContentResponse.text()
|
|
186
|
+
const contentType = uploadedContentResponse.headers.get('Content-Type')
|
|
175
187
|
|
|
176
|
-
|
|
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)
|
|
177
193
|
|
|
178
|
-
|
|
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')
|
|
179
197
|
|
|
180
|
-
|
|
198
|
+
const uploadedResponse = await fetch(created, {
|
|
199
|
+
method: 'put',
|
|
200
|
+
body: formData
|
|
201
|
+
})
|
|
202
|
+
await checkResponse(uploadedResponse, t)
|
|
181
203
|
|
|
182
|
-
|
|
204
|
+
const file2URL = new URL('/example2.txt', created)
|
|
205
|
+
const deleteResponse = await fetch(file2URL, {
|
|
206
|
+
method: 'delete'
|
|
183
207
|
})
|
|
184
208
|
|
|
185
|
-
|
|
186
|
-
|
|
209
|
+
await checkResponse(deleteResponse, t, 'Able to DELETE')
|
|
210
|
+
|
|
211
|
+
const dirResponse = await fetch(created)
|
|
212
|
+
|
|
213
|
+
await checkResponse(dirResponse, t)
|
|
187
214
|
|
|
188
|
-
|
|
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)
|
|
219
|
+
|
|
220
|
+
const uploadLocation = new URL('./subfolder/example.txt', created)
|
|
221
|
+
|
|
222
|
+
const uploadResponse = await fetch(uploadLocation, {
|
|
223
|
+
method: 'put',
|
|
224
|
+
body: SAMPLE_CONTENT
|
|
189
225
|
})
|
|
226
|
+
await checkResponse(uploadResponse, t)
|
|
190
227
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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)
|
|
197
247
|
|
|
198
|
-
|
|
199
|
-
t.equal(response.headers.get('Content-Type'), 'text/event-stream', 'Response is event stream')
|
|
248
|
+
const uploadedContentResponse = await fetch(uploadLocation)
|
|
200
249
|
|
|
201
|
-
|
|
250
|
+
await checkResponse(uploadedContentResponse, t)
|
|
202
251
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
fetch('hyper://example/example4.txt', { method: 'PUT', body: 'Hello World' })
|
|
206
|
-
])
|
|
252
|
+
const content = await uploadedContentResponse.text()
|
|
253
|
+
const contentType = uploadedContentResponse.headers.get('Content-Type')
|
|
207
254
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
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)
|
|
211
261
|
|
|
212
|
-
|
|
262
|
+
const uploadResponse = await fetch(uploadLocation, {
|
|
263
|
+
method: 'put',
|
|
264
|
+
body: SAMPLE_CONTENT
|
|
213
265
|
})
|
|
266
|
+
await checkResponse(uploadResponse, t)
|
|
214
267
|
|
|
215
|
-
|
|
216
|
-
const domainResponse = await fetch('hyper://example/.well-known/hyper')
|
|
217
|
-
const domain = (await domainResponse.text()).split('\n')[0]
|
|
268
|
+
const noResolve = created + '?noResolve'
|
|
218
269
|
|
|
219
|
-
|
|
220
|
-
|
|
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.skip('Read directory as HTML', async (t) => {
|
|
221
276
|
|
|
222
|
-
|
|
223
|
-
await fetch(extensionURL)
|
|
224
|
-
// Load up extension message on peer 2
|
|
225
|
-
await fetch2(extensionURL)
|
|
277
|
+
})
|
|
226
278
|
|
|
227
|
-
|
|
279
|
+
test('EventSource extension messages', async (t) => {
|
|
280
|
+
const domain = await nextURL(t)
|
|
228
281
|
|
|
229
|
-
|
|
230
|
-
|
|
282
|
+
const extensionURL = `${domain}$/extensions/example`
|
|
283
|
+
const extensionListURL = `${domain}$/extensions/`
|
|
231
284
|
|
|
232
|
-
|
|
233
|
-
|
|
285
|
+
// Load up extension message on peer 1
|
|
286
|
+
const extensionLoadResponse1 = await fetch(extensionURL)
|
|
287
|
+
await checkResponse(extensionLoadResponse1, t)
|
|
288
|
+
// Load up extension message on peer 2
|
|
289
|
+
const extensionLoadResponse2 = await fetch2(extensionURL)
|
|
290
|
+
await checkResponse(extensionLoadResponse2, t)
|
|
234
291
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
await delay(2000)
|
|
292
|
+
const extensionListRequest = await fetch(extensionListURL)
|
|
293
|
+
const extensionList = await extensionListRequest.json()
|
|
238
294
|
|
|
239
|
-
|
|
240
|
-
|
|
295
|
+
// Extension list will always be alphabetically sorted
|
|
296
|
+
t.deepEqual(extensionList, ['example'], 'Got expected list of extensions')
|
|
241
297
|
|
|
242
|
-
|
|
298
|
+
const peerResponse1 = await fetch(extensionURL)
|
|
299
|
+
const peerList1 = await peerResponse1.json()
|
|
243
300
|
|
|
244
|
-
|
|
245
|
-
const peerList2 = await peerResponse2.json()
|
|
301
|
+
t.equal(peerList1.length, 1, 'Got one peer for extension message on peer1')
|
|
246
302
|
|
|
247
|
-
|
|
303
|
+
const peerResponse2 = await fetch2(extensionURL)
|
|
304
|
+
const peerList2 = await peerResponse2.json()
|
|
248
305
|
|
|
249
|
-
|
|
250
|
-
headers: {
|
|
251
|
-
Accept: 'text/event-stream'
|
|
252
|
-
}
|
|
253
|
-
})
|
|
306
|
+
t.equal(peerList2.length, 1, 'Got one peer for extension message on peer2')
|
|
254
307
|
|
|
255
|
-
|
|
256
|
-
|
|
308
|
+
const { EventSource } = createEventSource(fetch)
|
|
309
|
+
const source = new EventSource(extensionListURL)
|
|
257
310
|
|
|
258
|
-
|
|
311
|
+
await Promise.race([
|
|
312
|
+
once(source, 'open'),
|
|
313
|
+
once(source, 'error').then(([e]) => { throw e })
|
|
314
|
+
])
|
|
259
315
|
|
|
260
|
-
|
|
316
|
+
const toRead = Promise.race([
|
|
317
|
+
once(source, 'example'),
|
|
318
|
+
once(source, 'error').then(([e]) => { throw e })
|
|
319
|
+
])
|
|
261
320
|
|
|
262
|
-
|
|
321
|
+
const broadcastRequest = await fetch2(extensionURL, { method: 'POST', body: SAMPLE_CONTENT })
|
|
263
322
|
|
|
264
|
-
|
|
323
|
+
t.ok(broadcastRequest.ok, 'Able to broadcast to peers')
|
|
265
324
|
|
|
266
|
-
|
|
325
|
+
const [event] = await toRead
|
|
267
326
|
|
|
268
|
-
|
|
327
|
+
const { type, data, lastEventId } = event
|
|
269
328
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
t.ok(data.value.endsWith('\n\n'), 'Ends with two newlines')
|
|
275
|
-
|
|
276
|
-
await reader.cancel()
|
|
277
|
-
})
|
|
278
|
-
}
|
|
329
|
+
t.equal(data, SAMPLE_CONTENT, 'Got data from event')
|
|
330
|
+
t.equal(type, 'example', 'Event got set to extension message name')
|
|
331
|
+
t.ok(lastEventId, 'Event contained peer ID')
|
|
332
|
+
})
|
|
279
333
|
|
|
280
|
-
function
|
|
281
|
-
|
|
334
|
+
async function checkResponse (response, t, successMessage = 'Response OK') {
|
|
335
|
+
if (!response.ok) {
|
|
336
|
+
const message = await response.text()
|
|
337
|
+
t.fail(new Error(`HTTP Error ${response.status}:\n${message}`))
|
|
338
|
+
} else {
|
|
339
|
+
t.pass(successMessage)
|
|
340
|
+
}
|
|
282
341
|
}
|
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
|
-
}
|