hypercore-fetch 8.6.2-0 → 9.0.1
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 +1 -1
- package/index.js +37 -11
- package/package.json +4 -3
- package/test.js +57 -3
package/index.js
CHANGED
|
@@ -293,7 +293,7 @@ export default async function makeHyperFetch ({
|
|
|
293
293
|
const contentType = request.headers.get('Content-Type') || ''
|
|
294
294
|
const isFormData = contentType.includes('multipart/form-data')
|
|
295
295
|
|
|
296
|
-
const drive = await getDrive(hostname)
|
|
296
|
+
const drive = await getDrive(`hyper://${hostname}`)
|
|
297
297
|
|
|
298
298
|
if (isFormData) {
|
|
299
299
|
// It's a form! Get the files out and process them
|
|
@@ -317,13 +317,12 @@ export default async function makeHyperFetch ({
|
|
|
317
317
|
)
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
|
|
321
|
-
return { status: 200 }
|
|
320
|
+
return { status: 201, headers: { Location: request.url } }
|
|
322
321
|
})
|
|
323
322
|
router.delete('hyper://*/**', async function putFiles (request) {
|
|
324
323
|
const { hostname, pathname } = new URL(request.url)
|
|
325
324
|
|
|
326
|
-
const drive = await getDrive(hostname)
|
|
325
|
+
const drive = await getDrive(`hyper://${hostname}`)
|
|
327
326
|
|
|
328
327
|
if (pathname.endsWith('/')) {
|
|
329
328
|
let didDelete = false
|
|
@@ -356,7 +355,7 @@ export default async function makeHyperFetch ({
|
|
|
356
355
|
const noResolve = searchParams.has('noResolve')
|
|
357
356
|
const isDirectory = pathname.endsWith('/')
|
|
358
357
|
|
|
359
|
-
const drive = await getDrive(hostname)
|
|
358
|
+
const drive = await getDrive(`hyper://${hostname}`)
|
|
360
359
|
|
|
361
360
|
const resHeaders = {
|
|
362
361
|
ETag: `${drive.version}`,
|
|
@@ -409,7 +408,8 @@ export default async function makeHyperFetch ({
|
|
|
409
408
|
}
|
|
410
409
|
}
|
|
411
410
|
}
|
|
412
|
-
|
|
411
|
+
|
|
412
|
+
const { entry, path } = await resolvePath(drive, pathname, noResolve)
|
|
413
413
|
|
|
414
414
|
if (!entry) {
|
|
415
415
|
return { status: 404, body: 'Not Found' }
|
|
@@ -417,7 +417,7 @@ export default async function makeHyperFetch ({
|
|
|
417
417
|
|
|
418
418
|
resHeaders.ETag = `${entry.seq}`
|
|
419
419
|
|
|
420
|
-
const contentType = getMimeType(
|
|
420
|
+
const contentType = getMimeType(path)
|
|
421
421
|
resHeaders['Content-Type'] = contentType
|
|
422
422
|
|
|
423
423
|
if (entry.metadata?.mtime) {
|
|
@@ -458,7 +458,7 @@ export default async function makeHyperFetch ({
|
|
|
458
458
|
const noResolve = searchParams.has('noResolve')
|
|
459
459
|
const isDirectory = pathname.endsWith('/')
|
|
460
460
|
|
|
461
|
-
const drive = await getDrive(hostname)
|
|
461
|
+
const drive = await getDrive(`hyper://${hostname}`)
|
|
462
462
|
|
|
463
463
|
if (isDirectory) {
|
|
464
464
|
const resHeaders = {
|
|
@@ -486,7 +486,7 @@ export default async function makeHyperFetch ({
|
|
|
486
486
|
}
|
|
487
487
|
|
|
488
488
|
if (accept.includes('text/html')) {
|
|
489
|
-
const body = renderIndex(url, entries, fetch)
|
|
489
|
+
const body = await renderIndex(url, entries, fetch)
|
|
490
490
|
return {
|
|
491
491
|
status: 200,
|
|
492
492
|
body,
|
|
@@ -506,13 +506,14 @@ export default async function makeHyperFetch ({
|
|
|
506
506
|
}
|
|
507
507
|
}
|
|
508
508
|
}
|
|
509
|
-
|
|
509
|
+
|
|
510
|
+
const { entry, path } = await resolvePath(drive, pathname, noResolve)
|
|
510
511
|
|
|
511
512
|
if (!entry) {
|
|
512
513
|
return { status: 404, body: 'Not Found' }
|
|
513
514
|
}
|
|
514
515
|
|
|
515
|
-
return serveFile(request.headers, drive,
|
|
516
|
+
return serveFile(request.headers, drive, path)
|
|
516
517
|
})
|
|
517
518
|
|
|
518
519
|
return fetch
|
|
@@ -568,6 +569,31 @@ async function serveFile (headers, drive, pathname) {
|
|
|
568
569
|
}
|
|
569
570
|
}
|
|
570
571
|
|
|
572
|
+
function makeToTry (pathname) {
|
|
573
|
+
return [
|
|
574
|
+
pathname,
|
|
575
|
+
pathname + '.html',
|
|
576
|
+
pathname + '.md'
|
|
577
|
+
]
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
async function resolvePath (drive, pathname, noResolve) {
|
|
581
|
+
if (noResolve) {
|
|
582
|
+
const entry = drive.entry(pathname)
|
|
583
|
+
|
|
584
|
+
return { entry, path: pathname }
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
for (const path of makeToTry(pathname)) {
|
|
588
|
+
const entry = await drive.entry(path)
|
|
589
|
+
if (entry) {
|
|
590
|
+
return { entry, path }
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
return { entry: null, path: null }
|
|
595
|
+
}
|
|
596
|
+
|
|
571
597
|
async function listEntries (drive, pathname = '/') {
|
|
572
598
|
const entries = []
|
|
573
599
|
for await (const path of drive.readdir(pathname)) {
|
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hypercore-fetch",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "9.0.1",
|
|
4
4
|
"description": "Implementation of Fetch that uses the Dat SDK for loading p2p content",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"main": "index.js",
|
|
6
7
|
"scripts": {
|
|
7
8
|
"test": "node test",
|
|
8
9
|
"lint": "standard --fix"
|
|
@@ -24,14 +25,14 @@
|
|
|
24
25
|
"dependencies": {
|
|
25
26
|
"event-iterator": "^2.0.0",
|
|
26
27
|
"hyperdrive": "^11.0.0-alpha.10",
|
|
27
|
-
"make-fetch": "^3.1.
|
|
28
|
+
"make-fetch": "^3.1.1",
|
|
28
29
|
"mime": "^3.0.0",
|
|
29
30
|
"range-parser": "^1.2.1",
|
|
30
31
|
"streamx": "^2.13.0"
|
|
31
32
|
},
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@rangermauve/fetch-event-source": "^1.0.3",
|
|
34
|
-
"hyper-sdk": "^4.1.
|
|
35
|
+
"hyper-sdk": "^4.1.1",
|
|
35
36
|
"standard": "^17.0.0",
|
|
36
37
|
"tape": "^5.2.2"
|
|
37
38
|
}
|
package/test.js
CHANGED
|
@@ -93,11 +93,11 @@ test('PUT file', async (t) => {
|
|
|
93
93
|
body: SAMPLE_CONTENT
|
|
94
94
|
})
|
|
95
95
|
|
|
96
|
-
await checkResponse(uploadResponse, t)
|
|
96
|
+
await checkResponse(uploadResponse, t, 'upload successful')
|
|
97
97
|
|
|
98
98
|
const uploadedContentResponse = await fetch(uploadLocation)
|
|
99
99
|
|
|
100
|
-
await checkResponse(uploadedContentResponse, t)
|
|
100
|
+
await checkResponse(uploadedContentResponse, t, 'able to load content')
|
|
101
101
|
|
|
102
102
|
const content = await uploadedContentResponse.text()
|
|
103
103
|
const contentType = uploadedContentResponse.headers.get('Content-Type')
|
|
@@ -272,8 +272,62 @@ test('Ignore index.html with noResolve', async (t) => {
|
|
|
272
272
|
const entries = await listDirRequest.json()
|
|
273
273
|
t.deepEqual(entries, ['index.html'], 'able to list index.html')
|
|
274
274
|
})
|
|
275
|
-
test
|
|
275
|
+
test('Read directory as HTML', async (t) => {
|
|
276
|
+
const created = await nextURL(t)
|
|
277
|
+
|
|
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)
|
|
287
|
+
|
|
288
|
+
const listDirRequest = await fetch(created, {
|
|
289
|
+
headers: {
|
|
290
|
+
Accept: 'text/html'
|
|
291
|
+
}
|
|
292
|
+
})
|
|
293
|
+
await checkResponse(listDirRequest, t, 'Able to list HTML')
|
|
294
|
+
|
|
295
|
+
const html = await listDirRequest.text()
|
|
296
|
+
|
|
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)
|
|
303
|
+
|
|
304
|
+
const uploadLocation = new URL('./example.md', created)
|
|
305
|
+
|
|
306
|
+
const uploadResponse = await fetch(uploadLocation, {
|
|
307
|
+
method: 'put',
|
|
308
|
+
body: SAMPLE_CONTENT
|
|
309
|
+
})
|
|
310
|
+
await checkResponse(uploadResponse, t)
|
|
311
|
+
|
|
312
|
+
const resolvedLocation = new URL('/example', created)
|
|
313
|
+
|
|
314
|
+
const uploadedContentResponse = await fetch(resolvedLocation)
|
|
315
|
+
|
|
316
|
+
await checkResponse(uploadedContentResponse, t, 'able to load content')
|
|
317
|
+
|
|
318
|
+
const content = await uploadedContentResponse.text()
|
|
319
|
+
const contentType = uploadedContentResponse.headers.get('Content-Type')
|
|
320
|
+
|
|
321
|
+
t.equal(content, SAMPLE_CONTENT, 'Got original content out')
|
|
322
|
+
t.equal(contentType, 'text/markdown; charset=utf-8', 'Got markdown mime type')
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
test('Doing a `GET` on an invalid domain should cause an error', async (t) => {
|
|
326
|
+
const url = 'hyper://example/'
|
|
327
|
+
|
|
328
|
+
const failedResponse = await fetch(url)
|
|
276
329
|
|
|
330
|
+
t.notOk(failedResponse.ok, 'Response errored out due to invalid domain')
|
|
277
331
|
})
|
|
278
332
|
|
|
279
333
|
test('EventSource extension messages', async (t) => {
|