@helia/verified-fetch 4.0.2 → 4.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 (48) hide show
  1. package/dist/index.min.js +69 -63
  2. package/dist/index.min.js.map +4 -4
  3. package/dist/src/constants.d.ts +1 -0
  4. package/dist/src/constants.d.ts.map +1 -1
  5. package/dist/src/constants.js +1 -0
  6. package/dist/src/constants.js.map +1 -1
  7. package/dist/src/plugins/plugin-handle-cbor.d.ts +17 -0
  8. package/dist/src/plugins/plugin-handle-cbor.d.ts.map +1 -0
  9. package/dist/src/plugins/plugin-handle-cbor.js +94 -0
  10. package/dist/src/plugins/plugin-handle-cbor.js.map +1 -0
  11. package/dist/src/plugins/plugin-handle-dag-cbor.d.ts.map +1 -1
  12. package/dist/src/plugins/plugin-handle-dag-cbor.js +16 -27
  13. package/dist/src/plugins/plugin-handle-dag-cbor.js.map +1 -1
  14. package/dist/src/plugins/plugin-handle-dag-pb.d.ts.map +1 -1
  15. package/dist/src/plugins/plugin-handle-dag-pb.js +14 -2
  16. package/dist/src/plugins/plugin-handle-dag-pb.js.map +1 -1
  17. package/dist/src/plugins/plugin-handle-dag-walk.d.ts.map +1 -1
  18. package/dist/src/plugins/plugin-handle-dag-walk.js +52 -7
  19. package/dist/src/plugins/plugin-handle-dag-walk.js.map +1 -1
  20. package/dist/src/plugins/plugin-handle-json.d.ts.map +1 -1
  21. package/dist/src/plugins/plugin-handle-json.js +5 -3
  22. package/dist/src/plugins/plugin-handle-json.js.map +1 -1
  23. package/dist/src/utils/byte-range-context.js +1 -1
  24. package/dist/src/utils/byte-range-context.js.map +1 -1
  25. package/dist/src/utils/dag-cbor-to-safe-json.d.ts +8 -0
  26. package/dist/src/utils/dag-cbor-to-safe-json.d.ts.map +1 -1
  27. package/dist/src/utils/dag-cbor-to-safe-json.js +46 -17
  28. package/dist/src/utils/dag-cbor-to-safe-json.js.map +1 -1
  29. package/dist/src/utils/get-content-type.js +2 -2
  30. package/dist/src/utils/get-content-type.js.map +1 -1
  31. package/dist/src/utils/select-output-type.d.ts.map +1 -1
  32. package/dist/src/utils/select-output-type.js +13 -1
  33. package/dist/src/utils/select-output-type.js.map +1 -1
  34. package/dist/src/verified-fetch.d.ts.map +1 -1
  35. package/dist/src/verified-fetch.js +4 -2
  36. package/dist/src/verified-fetch.js.map +1 -1
  37. package/package.json +4 -4
  38. package/src/constants.ts +1 -0
  39. package/src/plugins/plugin-handle-cbor.ts +107 -0
  40. package/src/plugins/plugin-handle-dag-cbor.ts +17 -27
  41. package/src/plugins/plugin-handle-dag-pb.ts +16 -2
  42. package/src/plugins/plugin-handle-dag-walk.ts +56 -7
  43. package/src/plugins/plugin-handle-json.ts +5 -3
  44. package/src/utils/byte-range-context.ts +1 -1
  45. package/src/utils/dag-cbor-to-safe-json.ts +55 -19
  46. package/src/utils/get-content-type.ts +2 -2
  47. package/src/utils/select-output-type.ts +13 -1
  48. package/src/verified-fetch.ts +4 -2
@@ -2,6 +2,7 @@ import * as ipldDagCbor from '@ipld/dag-cbor'
2
2
  import * as ipldDagJson from '@ipld/dag-json'
3
3
  import toBuffer from 'it-to-buffer'
4
4
  import { code as jsonCode } from 'multiformats/codecs/json'
5
+ import { CODEC_CBOR } from '../constants.ts'
5
6
  import { notAcceptableResponse, okRangeResponse } from '../utils/responses.js'
6
7
  import { BasePlugin } from './plugin-base.js'
7
8
  import type { PluginContext } from './types.js'
@@ -18,8 +19,9 @@ export class JsonPlugin extends BasePlugin {
18
19
  return false
19
20
  }
20
21
 
21
- if (accept?.mimeType === 'application/vnd.ipld.dag-json' && cid.code !== ipldDagCbor.code) {
22
- // we can handle application/vnd.ipld.dag-json, but if the CID codec is ipldDagCbor, DagCborPlugin should handle it
22
+ if (accept?.mimeType === 'application/vnd.ipld.dag-json' && cid.code !== ipldDagCbor.code && cid.code !== CODEC_CBOR) {
23
+ // we can handle application/vnd.ipld.dag-json, but if the CID codec is
24
+ // cbor related, cbor related plugins will handle it
23
25
  // TODO: remove the need for deny-listing cases in plugins
24
26
  return true
25
27
  }
@@ -47,7 +49,7 @@ export class JsonPlugin extends BasePlugin {
47
49
  const obj = ipldDagJson.decode(block)
48
50
  body = ipldDagCbor.encode(obj)
49
51
  } catch (err) {
50
- this.log.error('could not transform %c to application/vnd.ipld.dag-cbor', err)
52
+ this.log.error('could not transform %c to application/vnd.ipld.dag-cbor - %e', err)
51
53
  return notAcceptableResponse(resource)
52
54
  }
53
55
  } else {
@@ -588,7 +588,7 @@ export class ByteRangeContext {
588
588
 
589
589
  controller.close()
590
590
  } catch (err) {
591
- log.error('Error processing range(s): %o', err)
591
+ log.error('Error processing range(s) - %e', err)
592
592
  controller.error(err)
593
593
  }
594
594
  }
@@ -1,5 +1,27 @@
1
- import { decode } from 'cborg'
2
- import { encode } from 'cborg/json'
1
+ import { decode, encode } from 'cborg'
2
+ import { encode as jsonEncode } from 'cborg/json'
3
+ import { CID } from 'multiformats/cid'
4
+ import type { DecodeOptions } from 'cborg'
5
+
6
+ // https://github.com/ipfs/go-ipfs/issues/3570#issuecomment-273931692
7
+ const CID_CBOR_TAG = 42
8
+
9
+ const options: DecodeOptions = {
10
+ allowIndefinite: false,
11
+ coerceUndefinedToNull: false,
12
+ allowNaN: false,
13
+ allowInfinity: false,
14
+ strict: true,
15
+ useMaps: false,
16
+ rejectDuplicateMapKeys: true,
17
+ tags: [],
18
+
19
+ // this is different to `DAG-CBOR` - the reason we disallow BigInts is
20
+ // because we are about to re-encode to `JSON` which does not support
21
+ // BigInts. Blocks containing large numbers should be deserialized using a
22
+ // cbor decoder instead
23
+ allowBigInt: false.valueOf
24
+ }
3
25
 
4
26
  /**
5
27
  * Take a `DAG-CBOR` encoded `Uint8Array`, deserialize it as an object and
@@ -7,21 +29,35 @@ import { encode } from 'cborg/json'
7
29
  * `JSON.parse` without losing any data.
8
30
  */
9
31
  export function dagCborToSafeJSON (buf: Uint8Array): string {
10
- const obj = decode(buf, {
11
- allowIndefinite: false,
12
- coerceUndefinedToNull: false,
13
- allowNaN: false,
14
- allowInfinity: false,
15
- strict: true,
16
- useMaps: false,
17
- rejectDuplicateMapKeys: true,
18
-
19
- // this is different to `DAG-CBOR` - the reason we disallow BigInts is
20
- // because we are about to re-encode to `JSON` which does not support
21
- // BigInts. Blocks containing large numbers should be deserialized using a
22
- // cbor decoder instead
23
- allowBigInt: false
24
- })
25
-
26
- return new TextDecoder().decode(encode(obj))
32
+ const opts: DecodeOptions = {
33
+ ...options,
34
+ tags: []
35
+ }
36
+ opts.tags[CID_CBOR_TAG] = (bytes: Uint8Array): any => {
37
+ if (bytes[0] !== 0) {
38
+ throw new Error('Invalid CID for CBOR tag 42; expected leading 0x00')
39
+ }
40
+
41
+ return {
42
+ '/': CID.decode(bytes.subarray(1)).toString() // ignore leading 0x00
43
+ }
44
+ }
45
+
46
+ const obj = decode(buf, opts)
47
+
48
+ return new TextDecoder().decode(jsonEncode(obj))
49
+ }
50
+
51
+ /**
52
+ * Decode CBOR to object without CID tag support
53
+ */
54
+ export function cborToObject (buf: Uint8Array): any {
55
+ return decode(buf, options)
56
+ }
57
+
58
+ /**
59
+ * Decode CBOR to object without CID tag support
60
+ */
61
+ export function objectToCbor (obj: any): Uint8Array {
62
+ return encode(obj, options)
27
63
  }
@@ -41,9 +41,9 @@ export async function getContentType ({ bytes, path, contentTypeParser, log, def
41
41
  } else if (parsed != null) {
42
42
  contentType = parsed
43
43
  }
44
- log.trace('contentTypeParser returned %s', contentType)
44
+ log.trace('contentTypeParser returned %s for file with name %s', contentType, fileName)
45
45
  } catch (err) {
46
- log.error('error parsing content type', err)
46
+ log.error('error parsing content type - %e', err)
47
47
  }
48
48
  }
49
49
 
@@ -3,6 +3,7 @@ import { code as dagJsonCode } from '@ipld/dag-json'
3
3
  import { code as dagPbCode } from '@ipld/dag-pb'
4
4
  import { code as jsonCode } from 'multiformats/codecs/json'
5
5
  import { code as rawCode } from 'multiformats/codecs/raw'
6
+ import { CODEC_CBOR } from '../constants.ts'
6
7
  import type { RequestFormatShorthand } from '../index.js'
7
8
  import type { CID } from 'multiformats/cid'
8
9
 
@@ -59,6 +60,17 @@ const CID_TYPE_MAP: Record<number, string[]> = {
59
60
  'application/vnd.ipld.dag-json',
60
61
  'application/vnd.ipld.car',
61
62
  'application/x-tar'
63
+ ],
64
+ [CODEC_CBOR]: [
65
+ 'application/json',
66
+ 'application/vnd.ipld.dag-cbor',
67
+ 'application/cbor',
68
+ 'application/vnd.ipld.dag-json',
69
+ 'application/octet-stream',
70
+ 'application/vnd.ipld.raw',
71
+ 'application/vnd.ipfs.ipns-record',
72
+ 'application/vnd.ipld.car',
73
+ 'text/html'
62
74
  ]
63
75
  }
64
76
 
@@ -71,7 +83,7 @@ export interface AcceptHeader {
71
83
  * Selects an output mime-type based on the CID and a passed `Accept` header
72
84
  */
73
85
  export function selectOutputType (cid: CID, accept?: string): AcceptHeader | undefined {
74
- const cidMimeTypes = CID_TYPE_MAP[cid.code]
86
+ const cidMimeTypes = CID_TYPE_MAP[cid.code] ?? []
75
87
 
76
88
  if (accept != null) {
77
89
  return chooseMimeType(accept, cidMimeTypes)
@@ -5,6 +5,7 @@ import { CustomProgressEvent } from 'progress-events'
5
5
  import QuickLRU from 'quick-lru'
6
6
  import { ByteRangeContextPlugin } from './plugins/plugin-handle-byte-range-context.js'
7
7
  import { CarPlugin } from './plugins/plugin-handle-car.js'
8
+ import { CborPlugin } from './plugins/plugin-handle-cbor.js'
8
9
  import { DagCborPlugin } from './plugins/plugin-handle-dag-cbor.js'
9
10
  import { DagPbPlugin } from './plugins/plugin-handle-dag-pb.js'
10
11
  import { DagWalkPlugin } from './plugins/plugin-handle-dag-walk.js'
@@ -99,7 +100,8 @@ export class VerifiedFetch {
99
100
  new TarPlugin(pluginOptions),
100
101
  new JsonPlugin(pluginOptions),
101
102
  new DagCborPlugin(pluginOptions),
102
- new DagPbPlugin(pluginOptions)
103
+ new DagPbPlugin(pluginOptions),
104
+ new CborPlugin(pluginOptions)
103
105
  ]
104
106
 
105
107
  const customPlugins = init.plugins?.map((pluginFactory) => pluginFactory(pluginOptions)) ?? []
@@ -245,7 +247,7 @@ export class VerifiedFetch {
245
247
  this.log(`starting pipeline pass #${passCount + 1}`)
246
248
  passCount++
247
249
 
248
- this.log.trace('checking which plugins can handle %c%s with accept %o', context.cid, context.path != null ? `/${context.path}` : '', context.accept)
250
+ this.log.trace('checking which plugins can handle %c%s with accept %o', context.cid, context.path.length > 0 ? `/${context.path.join('/')}` : '', context.accept)
249
251
 
250
252
  // gather plugins that say they can handle the *current* context, but haven't been used yet
251
253
  const readyPlugins = this.plugins.filter(p => !pluginsUsed.has(p.id)).filter(p => p.canHandle(context))