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.
@@ -7,7 +7,7 @@ jobs:
7
7
  continue-on-error: true
8
8
  strategy:
9
9
  matrix:
10
- node: [ '16' ]
10
+ node: [ '18' ]
11
11
  os: [ubuntu-latest, windows-latest, macOS-latest]
12
12
  runs-on: ${{ matrix.os }}
13
13
  name: Node ${{ matrix.node }}-${{matrix.os}} tests
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
- // TODO: Use 201 with location in response headers
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
- const entry = await drive.entry(pathname)
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(pathname)
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
- const entry = await drive.entry(pathname)
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, pathname)
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": "8.6.2-0",
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.0",
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.0",
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.skip('Read directory as HTML', async (t) => {
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) => {