@helia/verified-fetch 0.0.0-75d0a5b → 0.0.0-7c07e11

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.
@@ -1,20 +1,20 @@
1
- import { dagCbor as heliaDagCbor, type DAGCBOR } from '@helia/dag-cbor'
2
- import { dagJson as heliaDagJson, type DAGJSON } from '@helia/dag-json'
3
1
  import { ipns as heliaIpns, type IPNS } from '@helia/ipns'
4
2
  import { dnsJsonOverHttps } from '@helia/ipns/dns-resolvers'
5
- import { json as heliaJson, type JSON } from '@helia/json'
6
3
  import { unixfs as heliaUnixFs, type UnixFS as HeliaUnixFs, type UnixFSStats } from '@helia/unixfs'
7
4
  import { code as dagCborCode } from '@ipld/dag-cbor'
8
5
  import { code as dagJsonCode } from '@ipld/dag-json'
9
6
  import { code as dagPbCode } from '@ipld/dag-pb'
10
7
  import { code as jsonCode } from 'multiformats/codecs/json'
11
- import { decode, code as rawCode } from 'multiformats/codecs/raw'
8
+ import { code as rawCode } from 'multiformats/codecs/raw'
12
9
  import { identity } from 'multiformats/hashes/identity'
13
10
  import { CustomProgressEvent } from 'progress-events'
11
+ import { dagCborToSafeJSON } from './utils/dag-cbor-to-safe-json.js'
12
+ import { getETag } from './utils/get-e-tag.js'
14
13
  import { getStreamFromAsyncIterable } from './utils/get-stream-from-async-iterable.js'
15
14
  import { parseResource } from './utils/parse-resource.js'
16
15
  import { walkPath, type PathWalkerFn } from './utils/walk-path.js'
17
16
  import type { CIDDetail, ContentTypeParser, Resource, VerifiedFetchInit as VerifiedFetchOptions } from './index.js'
17
+ import type { RequestFormatShorthand } from './types.js'
18
18
  import type { Helia } from '@helia/interface'
19
19
  import type { AbortOptions, Logger } from '@libp2p/interface'
20
20
  import type { UnixFSEntry } from 'ipfs-unixfs-exporter'
@@ -24,9 +24,6 @@ interface VerifiedFetchComponents {
24
24
  helia: Helia
25
25
  ipns?: IPNS
26
26
  unixfs?: HeliaUnixFs
27
- dagJson?: DAGJSON
28
- json?: JSON
29
- dagCbor?: DAGCBOR
30
27
  pathWalker?: PathWalkerFn
31
28
  }
32
29
 
@@ -81,14 +78,11 @@ export class VerifiedFetch {
81
78
  private readonly helia: Helia
82
79
  private readonly ipns: IPNS
83
80
  private readonly unixfs: HeliaUnixFs
84
- private readonly dagJson: DAGJSON
85
- private readonly dagCbor: DAGCBOR
86
- private readonly json: JSON
87
81
  private readonly pathWalker: PathWalkerFn
88
82
  private readonly log: Logger
89
83
  private readonly contentTypeParser: ContentTypeParser | undefined
90
84
 
91
- constructor ({ helia, ipns, unixfs, dagJson, json, dagCbor, pathWalker }: VerifiedFetchComponents, init?: VerifiedFetchInit) {
85
+ constructor ({ helia, ipns, unixfs, pathWalker }: VerifiedFetchComponents, init?: VerifiedFetchInit) {
92
86
  this.helia = helia
93
87
  this.log = helia.logger.forComponent('helia:verified-fetch')
94
88
  this.ipns = ipns ?? heliaIpns(helia, {
@@ -98,9 +92,6 @@ export class VerifiedFetch {
98
92
  ]
99
93
  })
100
94
  this.unixfs = unixfs ?? heliaUnixFs(helia)
101
- this.dagJson = dagJson ?? heliaDagJson(helia)
102
- this.json = json ?? heliaJson(helia)
103
- this.dagCbor = dagCbor ?? heliaDagCbor(helia)
104
95
  this.pathWalker = pathWalker ?? walkPath
105
96
  this.contentTypeParser = init?.contentTypeParser
106
97
  this.log.trace('created VerifiedFetch instance')
@@ -120,42 +111,36 @@ export class VerifiedFetch {
120
111
  return response
121
112
  }
122
113
 
123
- private async handleDagJson ({ cid, path, options }: FetchHandlerFunctionArg): Promise<Response> {
124
- this.log.trace('fetching %c/%s', cid, path)
125
- options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:start', { cid, path }))
126
- const result = await this.dagJson.get(cid, {
127
- signal: options?.signal,
128
- onProgress: options?.onProgress
129
- })
130
- options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid, path }))
131
- const response = okResponse(JSON.stringify(result))
132
- response.headers.set('content-type', 'application/json')
133
- return response
134
- }
135
-
136
114
  private async handleJson ({ cid, path, options }: FetchHandlerFunctionArg): Promise<Response> {
137
115
  this.log.trace('fetching %c/%s', cid, path)
138
116
  options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:start', { cid, path }))
139
- const result: Record<any, any> = await this.json.get(cid, {
117
+ const result = await this.helia.blockstore.get(cid, {
140
118
  signal: options?.signal,
141
119
  onProgress: options?.onProgress
142
120
  })
143
- options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid, path }))
144
- const response = okResponse(JSON.stringify(result))
121
+ const response = okResponse(result)
145
122
  response.headers.set('content-type', 'application/json')
123
+ options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid, path }))
146
124
  return response
147
125
  }
148
126
 
149
127
  private async handleDagCbor ({ cid, path, options }: FetchHandlerFunctionArg): Promise<Response> {
150
128
  this.log.trace('fetching %c/%s', cid, path)
151
129
  options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:start', { cid, path }))
152
- const result = await this.dagCbor.get<Uint8Array>(cid, {
153
- signal: options?.signal,
154
- onProgress: options?.onProgress
155
- })
130
+ // return body as binary
131
+ const block = await this.helia.blockstore.get(cid)
132
+ let body: string | Uint8Array
133
+
134
+ try {
135
+ body = dagCborToSafeJSON(block)
136
+ } catch (err) {
137
+ this.log('could not decode DAG-CBOR as JSON-safe, falling back to `application/octet-stream`', err)
138
+ body = block
139
+ }
140
+
141
+ const response = okResponse(body)
142
+ response.headers.set('content-type', body instanceof Uint8Array ? 'application/octet-stream' : 'application/json')
156
143
  options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid, path }))
157
- const response = okResponse(JSON.stringify(result))
158
- await this.setContentType(result, path, response)
159
144
  return response
160
145
  }
161
146
 
@@ -192,7 +177,6 @@ export class VerifiedFetch {
192
177
  signal: options?.signal,
193
178
  onProgress: options?.onProgress
194
179
  })
195
- options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid: resolvedCID, path: '' }))
196
180
  this.log('got async iterator for %c/%s', cid, path)
197
181
 
198
182
  const { stream, firstChunk } = await getStreamFromAsyncIterable(asyncIter, path ?? '', this.helia.logger, {
@@ -201,6 +185,8 @@ export class VerifiedFetch {
201
185
  const response = okResponse(stream)
202
186
  await this.setContentType(firstChunk, path, response)
203
187
 
188
+ options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid: resolvedCID, path: '' }))
189
+
204
190
  return response
205
191
  }
206
192
 
@@ -208,9 +194,10 @@ export class VerifiedFetch {
208
194
  this.log.trace('fetching %c/%s', cid, path)
209
195
  options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:start', { cid, path }))
210
196
  const result = await this.helia.blockstore.get(cid)
211
- options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid, path }))
212
- const response = okResponse(decode(result))
197
+ const response = okResponse(result)
213
198
  await this.setContentType(result, path, response)
199
+
200
+ options?.onProgress?.(new CustomProgressEvent<CIDDetail>('verified-fetch:request:end', { cid, path }))
214
201
  return response
215
202
  }
216
203
 
@@ -246,8 +233,8 @@ export class VerifiedFetch {
246
233
  * @see https://specs.ipfs.tech/http-gateways/path-gateway/#format-request-query-parameter
247
234
  * @default 'raw'
248
235
  */
249
- private getFormat ({ headerFormat, queryFormat }: { headerFormat: string | null, queryFormat: string | null }): string | null {
250
- const formatMap: Record<string, string> = {
236
+ private getFormat ({ headerFormat, queryFormat }: { headerFormat: string | null, queryFormat: RequestFormatShorthand | null }): RequestFormatShorthand | null {
237
+ const formatMap: Record<string, RequestFormatShorthand> = {
251
238
  'vnd.ipld.raw': 'raw',
252
239
  'vnd.ipld.car': 'car',
253
240
  'application/x-tar': 'tar',
@@ -287,8 +274,8 @@ export class VerifiedFetch {
287
274
  }
288
275
 
289
276
  private readonly codecHandlers: Record<number, FetchHandlerFunction> = {
290
- [dagJsonCode]: this.handleDagJson,
291
277
  [dagPbCode]: this.handleDagPb,
278
+ [dagJsonCode]: this.handleJson,
292
279
  [jsonCode]: this.handleJson,
293
280
  [dagCborCode]: this.handleDagCbor,
294
281
  [rawCode]: this.handleRaw,
@@ -338,8 +325,8 @@ export class VerifiedFetch {
338
325
  }
339
326
  }
340
327
 
341
- response.headers.set('etag', cid.toString()) // https://specs.ipfs.tech/http-gateways/path-gateway/#etag-response-header
342
- response.headers.set('cache-cotrol', 'public, max-age=29030400, immutable')
328
+ response.headers.set('etag', getETag({ cid, reqFormat: format ?? undefined, weak: false }))
329
+ response.headers.set('cache-control', 'public, max-age=29030400, immutable')
343
330
  response.headers.set('X-Ipfs-Path', resource.toString()) // https://specs.ipfs.tech/http-gateways/path-gateway/#x-ipfs-path-response-header
344
331
 
345
332
  if (ipfsRoots != null) {