hypercore-fetch 9.0.2 → 9.0.4

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.
Files changed (3) hide show
  1. package/index.js +26 -6
  2. package/package.json +1 -1
  3. package/test.js +28 -0
package/index.js CHANGED
@@ -23,6 +23,8 @@ const MIME_EVENT_STREAM = 'text/event-stream; charset=utf-8'
23
23
 
24
24
  const HEADER_CONTENT_TYPE = 'Content-Type'
25
25
 
26
+ export const ERROR_KEY_NOT_CREATED = 'Must create key with POST before reading'
27
+
26
28
  async function DEFAULT_RENDER_INDEX (url, files, fetch) {
27
29
  return `
28
30
  <!DOCTYPE html>
@@ -103,7 +105,7 @@ export default async function makeHyperFetch ({
103
105
  }
104
106
  const core = await getDBCoreForName(key)
105
107
  if (!core.length && errorOnNew) {
106
- return { status: 400, body: 'Must create key with POST before reading' }
108
+ throw new Error(ERROR_KEY_NOT_CREATED)
107
109
  }
108
110
 
109
111
  const corestore = sdk.namespace(key)
@@ -269,9 +271,21 @@ export default async function makeHyperFetch ({
269
271
  return { status: 400, body: 'Must specify key parameter to resolve' }
270
272
  }
271
273
 
272
- const drive = await getDriveFromKey(key, true)
274
+ try {
275
+ const drive = await getDriveFromKey(key, true)
273
276
 
274
- return { body: drive.core.url }
277
+ return { body: drive.core.url }
278
+ } catch (e) {
279
+ if (e.message === ERROR_KEY_NOT_CREATED) {
280
+ return {
281
+ status: 400,
282
+ body: e.message,
283
+ headers: {
284
+ [HEADER_CONTENT_TYPE]: MIME_TEXT_PLAIN
285
+ }
286
+ }
287
+ } else throw e
288
+ }
275
289
  })
276
290
  router.post(`hyper://${SPECIAL_DOMAIN}/`, async function createKey (request) {
277
291
  // TODO: Allow importing secret keys here
@@ -356,11 +370,12 @@ export default async function makeHyperFetch ({
356
370
  const isDirectory = pathname.endsWith('/')
357
371
 
358
372
  const drive = await getDrive(`hyper://${hostname}`)
373
+ const fullURL = new URL(pathname, drive.core.url).href
359
374
 
360
375
  const resHeaders = {
361
376
  ETag: `${drive.version}`,
362
377
  'Accept-Ranges': 'bytes',
363
- Link: `<${drive.core.url}>; rel="canonical"`
378
+ Link: `<${fullURL}>; rel="canonical"`
364
379
  }
365
380
 
366
381
  if (isDirectory) {
@@ -415,6 +430,8 @@ export default async function makeHyperFetch ({
415
430
  return { status: 404, body: 'Not Found' }
416
431
  }
417
432
 
433
+ resHeaders.Link = new URL(path, drive.core.url).href
434
+
418
435
  resHeaders.ETag = `${entry.seq}`
419
436
 
420
437
  const contentType = getMimeType(path)
@@ -459,11 +476,12 @@ export default async function makeHyperFetch ({
459
476
  const isDirectory = pathname.endsWith('/')
460
477
 
461
478
  const drive = await getDrive(`hyper://${hostname}`)
479
+ const fullURL = new URL(pathname, drive.core.url).href
462
480
 
463
481
  if (isDirectory) {
464
482
  const resHeaders = {
465
483
  ETag: `${drive.version}`,
466
- Link: `<${drive.core.url}>; rel="canonical"`
484
+ Link: `<${fullURL}>; rel="canonical"`
467
485
  }
468
486
 
469
487
  const entries = await listEntries(drive, pathname)
@@ -523,13 +541,15 @@ async function serveFile (headers, drive, pathname) {
523
541
  const isRanged = headers.get('Range') || ''
524
542
  const contentType = getMimeType(pathname)
525
543
 
544
+ const fullURL = new URL(pathname, drive.core.url).href
545
+
526
546
  const entry = await drive.entry(pathname)
527
547
 
528
548
  const resHeaders = {
529
549
  ETag: `${entry.seq}`,
530
550
  [HEADER_CONTENT_TYPE]: contentType,
531
551
  'Accept-Ranges': 'bytes',
532
- Link: `<${drive.core.url}>; rel="canonical"`
552
+ Link: `<${fullURL}>; rel="canonical"`
533
553
  }
534
554
 
535
555
  if (entry.metadata?.mtime) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hypercore-fetch",
3
- "version": "9.0.2",
3
+ "version": "9.0.4",
4
4
  "description": "Implementation of Fetch that uses the Dat SDK for loading p2p content",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/test.js CHANGED
@@ -72,7 +72,9 @@ test('Quick check', async (t) => {
72
72
 
73
73
  const content = await uploadedContentResponse.text()
74
74
  const contentType = uploadedContentResponse.headers.get('Content-Type')
75
+ const contentLink = uploadedContentResponse.headers.get('Link')
75
76
 
77
+ t.match(contentLink, /^<hyper:\/\/[0-9a-z]{52}\/example.txt>; rel="canonical"$/, 'Link header includes both public key and path.')
76
78
  t.equal(contentType, 'text/plain; charset=utf-8', 'Content got expected mime type')
77
79
  t.equal(content, SAMPLE_CONTENT, 'Got uploaded content back out')
78
80
 
@@ -83,6 +85,32 @@ test('Quick check', async (t) => {
83
85
  t.deepEqual(await dirResponse.json(), ['example.txt'], 'File got added')
84
86
  })
85
87
 
88
+ test('GET full url for created keys', async (t) => {
89
+ const keyURL = `hyper://localhost/?key=example${next()}`
90
+
91
+ const nonExistingResponse = await fetch(keyURL)
92
+
93
+ t.notOk(nonExistingResponse.ok, 'response has error before key is created')
94
+ const errorMessage = await nonExistingResponse.text()
95
+
96
+ t.equal(nonExistingResponse.status, 400, 'Got 400 error code')
97
+ t.notOk(errorMessage.startsWith('hyper://'), 'did not return hyper URL')
98
+
99
+ const createResponse = await fetch(keyURL, { method: 'post' })
100
+ await checkResponse(createResponse, t, 'Able to create drive')
101
+
102
+ const createdURL = await createResponse.text()
103
+
104
+ t.ok(createdURL.startsWith('hyper://'), 'Got new hyper:// URL')
105
+
106
+ const nowExistingResponse = await fetch(keyURL)
107
+ await checkResponse(nowExistingResponse, t,'GET no longer fails on create')
108
+
109
+ const existingURL = await nowExistingResponse.text()
110
+
111
+ t.equal(existingURL, createdURL, 'URL same as in initial create')
112
+ })
113
+
86
114
  test('PUT file', async (t) => {
87
115
  const created = await nextURL(t)
88
116