@helia/verified-fetch 7.2.16 → 8.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/README.md +8 -12
- package/dist/index.min.js +70 -59
- package/dist/index.min.js.map +4 -4
- package/dist/src/index.d.ts +18 -16
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +36 -34
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugins/plugin-handle-ipns-record.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-ipns-record.js +20 -6
- package/dist/src/plugins/plugin-handle-ipns-record.js.map +1 -1
- package/dist/src/plugins/plugin-handle-unixfs.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-unixfs.js +7 -4
- package/dist/src/plugins/plugin-handle-unixfs.js.map +1 -1
- package/dist/src/url-resolver.d.ts.map +1 -1
- package/dist/src/url-resolver.js +27 -9
- package/dist/src/url-resolver.js.map +1 -1
- package/dist/src/utils/abbreviate.d.ts.map +1 -1
- package/dist/src/utils/abbreviate.js +1 -0
- package/dist/src/utils/abbreviate.js.map +1 -1
- package/dist/src/utils/convert-output.d.ts +2 -2
- package/dist/src/utils/convert-output.d.ts.map +1 -1
- package/dist/src/utils/convert-output.js +11 -5
- package/dist/src/utils/convert-output.js.map +1 -1
- package/dist/src/utils/ipfs-path-to-cid.d.ts +6 -0
- package/dist/src/utils/ipfs-path-to-cid.d.ts.map +1 -0
- package/dist/src/utils/ipfs-path-to-cid.js +9 -0
- package/dist/src/utils/ipfs-path-to-cid.js.map +1 -0
- package/dist/src/utils/libp2p-defaults.browser.js +1 -1
- package/dist/src/utils/libp2p-defaults.browser.js.map +1 -1
- package/dist/src/utils/libp2p-defaults.d.ts.map +1 -1
- package/dist/src/utils/libp2p-defaults.js +2 -10
- package/dist/src/utils/libp2p-defaults.js.map +1 -1
- package/dist/src/verified-fetch.js +6 -6
- package/dist/src/verified-fetch.js.map +1 -1
- package/package.json +28 -31
- package/src/index.ts +51 -40
- package/src/plugins/plugin-handle-ipns-record.ts +25 -6
- package/src/plugins/plugin-handle-unixfs.ts +7 -4
- package/src/url-resolver.ts +35 -9
- package/src/utils/abbreviate.ts +1 -0
- package/src/utils/convert-output.ts +13 -7
- package/src/utils/ipfs-path-to-cid.ts +9 -0
- package/src/utils/libp2p-defaults.browser.ts +2 -2
- package/src/utils/libp2p-defaults.ts +3 -11
- package/src/verified-fetch.ts +6 -6
package/src/url-resolver.ts
CHANGED
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import { DoesNotExistError } from '@helia/unixfs/errors'
|
|
2
|
-
import
|
|
2
|
+
import * as cborg from 'cborg'
|
|
3
3
|
import { exporter, InvalidParametersError, walkPath } from 'ipfs-unixfs-exporter'
|
|
4
|
+
import last from 'it-last'
|
|
4
5
|
import toBuffer from 'it-to-buffer'
|
|
6
|
+
import { base58btc } from 'multiformats/bases/base58'
|
|
5
7
|
import { CID } from 'multiformats/cid'
|
|
8
|
+
import * as Digest from 'multiformats/hashes/digest'
|
|
6
9
|
import QuickLRU from 'quick-lru'
|
|
7
10
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
8
11
|
import { CODEC_LIBP2P_KEY, SESSION_CACHE_MAX_SIZE, SESSION_CACHE_TTL_MS } from './constants.ts'
|
|
9
12
|
import { abbreviate } from './utils/abbreviate.ts'
|
|
10
13
|
import { applyRedirects } from './utils/apply-redirect.ts'
|
|
14
|
+
import { splitIPNSName } from './utils/ipfs-path-to-cid.ts'
|
|
11
15
|
import { ServerTiming } from './utils/server-timing.ts'
|
|
12
16
|
import type { ResolveURLOptions, ResolveURLResult, URLResolver as URLResolverInterface } from './index.ts'
|
|
13
17
|
import type { DNSLink } from '@helia/dnslink'
|
|
@@ -16,6 +20,7 @@ import type { AbortOptions, Logger } from '@libp2p/interface'
|
|
|
16
20
|
import type { Helia, ProviderOptions, SessionBlockstore } from 'helia'
|
|
17
21
|
import type { Blockstore } from 'interface-blockstore'
|
|
18
22
|
import type { PathEntry, UnixFSEntry } from 'ipfs-unixfs-exporter'
|
|
23
|
+
import type { MultihashDigest } from 'multiformats/cid'
|
|
19
24
|
import type { ProgressOptions } from 'progress-events'
|
|
20
25
|
|
|
21
26
|
// 1 year in seconds for ipfs content
|
|
@@ -137,7 +142,7 @@ export class URLResolver implements URLResolverInterface {
|
|
|
137
142
|
|
|
138
143
|
if (result.namespace === 'ipns') {
|
|
139
144
|
// dnslink resolved to IPNS name
|
|
140
|
-
const ipnsUrl = new URL(`ipns://${result.
|
|
145
|
+
const ipnsUrl = new URL(`ipns://${base58btc.baseEncode(result.value.bytes)}${path}`)
|
|
141
146
|
resolveResult = await this.resolveIPNSName(ipnsUrl, serverTiming, options)
|
|
142
147
|
} else if (result.namespace === 'ipfs') {
|
|
143
148
|
// dnslink resolved to CID
|
|
@@ -161,11 +166,22 @@ export class URLResolver implements URLResolverInterface {
|
|
|
161
166
|
}
|
|
162
167
|
|
|
163
168
|
private async resolveIPNSName (url: URL, serverTiming: ServerTiming, options?: ResolveURLOptions): Promise<ResolveURLResult | Response> {
|
|
164
|
-
const
|
|
165
|
-
const result = await serverTiming.time(abbreviate('ipns.resolve'), '', this.components.ipnsResolver.resolve(
|
|
166
|
-
const path = normalizePath(`${result.path ?? ''}/${url.pathname}`)
|
|
169
|
+
const multihash = parseMultihash(url.hostname)
|
|
170
|
+
const result = await serverTiming.time(abbreviate('ipns.resolve'), '', last(this.components.ipnsResolver.resolve(multihash, options)))
|
|
167
171
|
|
|
168
|
-
|
|
172
|
+
if (result == null) {
|
|
173
|
+
throw new InvalidParametersError('Could not resolve IPNS name')
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const {
|
|
177
|
+
ns, name, path
|
|
178
|
+
} = splitIPNSName(result.value)
|
|
179
|
+
|
|
180
|
+
if (ns !== 'ipfs') {
|
|
181
|
+
throw new InvalidParametersError('IPNS name resolved to non-IPFS path')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const ipfsUrl = new URL(`ipfs://${name}${normalizePath(`${path ?? ''}/${url.pathname}`)}`)
|
|
169
185
|
const ipfsResult = await this.resolveIPFSPath(ipfsUrl, serverTiming, options)
|
|
170
186
|
|
|
171
187
|
if (ipfsResult instanceof Response) {
|
|
@@ -173,9 +189,11 @@ export class URLResolver implements URLResolverInterface {
|
|
|
173
189
|
}
|
|
174
190
|
|
|
175
191
|
let expires: Date | undefined
|
|
192
|
+
const data = cborg.decode(result.record.data ?? new Uint8Array(0))
|
|
176
193
|
|
|
177
|
-
|
|
178
|
-
|
|
194
|
+
// 0 is EOL
|
|
195
|
+
if (data.ValidityType === 0 && data.Validity instanceof Uint8Array) {
|
|
196
|
+
expires = new Date(uint8ArrayToString(data.Validity))
|
|
179
197
|
}
|
|
180
198
|
|
|
181
199
|
return {
|
|
@@ -197,7 +215,7 @@ export class URLResolver implements URLResolverInterface {
|
|
|
197
215
|
|
|
198
216
|
if (walkPathResult.terminalElement.cid.code === CODEC_LIBP2P_KEY) {
|
|
199
217
|
// special case, peer id encoded as libp2p key CID - interpret as IPNS
|
|
200
|
-
const ipnsUrl = new URL(`ipns://${
|
|
218
|
+
const ipnsUrl = new URL(`ipns://${base58btc.baseEncode(walkPathResult.terminalElement.cid.multihash.bytes)}`)
|
|
201
219
|
const ipnsResult = await this.resolveIPNSName(ipnsUrl, serverTiming, options)
|
|
202
220
|
|
|
203
221
|
if (ipnsResult instanceof Response) {
|
|
@@ -339,3 +357,11 @@ function normalizePath (path: string): string {
|
|
|
339
357
|
|
|
340
358
|
return ''
|
|
341
359
|
}
|
|
360
|
+
|
|
361
|
+
function parseMultihash (str: string): MultihashDigest {
|
|
362
|
+
if (str.startsWith('1') || str.startsWith('Q')) {
|
|
363
|
+
return Digest.decode(base58btc.baseDecode(str))
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
return CID.parse(str).multihash
|
|
367
|
+
}
|
package/src/utils/abbreviate.ts
CHANGED
|
@@ -4,12 +4,13 @@ import * as dagPb from '@ipld/dag-pb'
|
|
|
4
4
|
import * as json from 'multiformats/codecs/json'
|
|
5
5
|
import * as raw from 'multiformats/codecs/raw'
|
|
6
6
|
import { identity } from 'multiformats/hashes/identity'
|
|
7
|
+
import { withArrayBuffer } from 'uint8arrays/with-array-buffer'
|
|
7
8
|
import { CODEC_CBOR } from '../constants.ts'
|
|
8
9
|
import { getContentTypesForCid, MEDIA_TYPE_CBOR, MEDIA_TYPE_DAG_CBOR, MEDIA_TYPE_DAG_JSON, MEDIA_TYPE_JSON, MEDIA_TYPE_OCTET_STREAM, MEDIA_TYPE_RAW } from './content-types.ts'
|
|
9
10
|
import type { AcceptHeader, ContentType } from '../index.ts'
|
|
10
11
|
import type { CID } from 'multiformats/cid'
|
|
11
12
|
|
|
12
|
-
const CONVERSIONS: Record<number, Record<string, (buf: Uint8Array) => Uint8Array
|
|
13
|
+
const CONVERSIONS: Record<number, Record<string, (buf: Uint8Array<ArrayBuffer>) => Uint8Array<ArrayBuffer>>> = {
|
|
13
14
|
[dagCbor.code]: {
|
|
14
15
|
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
15
16
|
return buf
|
|
@@ -18,7 +19,8 @@ const CONVERSIONS: Record<number, Record<string, (buf: Uint8Array) => Uint8Array
|
|
|
18
19
|
return buf
|
|
19
20
|
},
|
|
20
21
|
[MEDIA_TYPE_JSON]: (buf) => {
|
|
21
|
-
return
|
|
22
|
+
// TODO: remove withArrayBuffer when dag-json is explicit about it's return type
|
|
23
|
+
return withArrayBuffer(dagJson.encode(dagCbor.decode(buf)))
|
|
22
24
|
},
|
|
23
25
|
[MEDIA_TYPE_DAG_JSON]: () => {
|
|
24
26
|
throw new Error('Cannot perform conversion since IPIP-0524')
|
|
@@ -41,7 +43,8 @@ const CONVERSIONS: Record<number, Record<string, (buf: Uint8Array) => Uint8Array
|
|
|
41
43
|
return buf
|
|
42
44
|
},
|
|
43
45
|
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
44
|
-
return
|
|
46
|
+
// TODO: remove withArrayBuffer when dag-json is explicit about it's return type
|
|
47
|
+
return withArrayBuffer(dagJson.encode(dagCbor.decode(buf)))
|
|
45
48
|
},
|
|
46
49
|
[MEDIA_TYPE_RAW]: (buf) => {
|
|
47
50
|
return buf
|
|
@@ -75,7 +78,8 @@ const CONVERSIONS: Record<number, Record<string, (buf: Uint8Array) => Uint8Array
|
|
|
75
78
|
return buf
|
|
76
79
|
},
|
|
77
80
|
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
78
|
-
return
|
|
81
|
+
// TODO: remove withArrayBuffer when dag-cbor is explicit about it's return type
|
|
82
|
+
return withArrayBuffer(dagCbor.encode(json.decode(buf)))
|
|
79
83
|
},
|
|
80
84
|
[MEDIA_TYPE_JSON]: (buf) => {
|
|
81
85
|
return buf
|
|
@@ -135,13 +139,15 @@ const CONVERSIONS: Record<number, Record<string, (buf: Uint8Array) => Uint8Array
|
|
|
135
139
|
return buf
|
|
136
140
|
},
|
|
137
141
|
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
138
|
-
return
|
|
142
|
+
// TODO: remove withArrayBuffer when dag-cbor is explicit about it's return type
|
|
143
|
+
return withArrayBuffer(dagCbor.encode(buf))
|
|
139
144
|
},
|
|
140
145
|
[MEDIA_TYPE_JSON]: (buf) => {
|
|
141
146
|
return buf
|
|
142
147
|
},
|
|
143
148
|
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
144
|
-
return
|
|
149
|
+
// TODO: remove withArrayBuffer when dag-json is explicit about it's return type
|
|
150
|
+
return withArrayBuffer(dagJson.encode(buf))
|
|
145
151
|
},
|
|
146
152
|
[MEDIA_TYPE_RAW]: (buf) => {
|
|
147
153
|
return buf
|
|
@@ -163,7 +169,7 @@ export interface ConvertedOutput {
|
|
|
163
169
|
* the deserialized value to that format and serialize it back to a block -
|
|
164
170
|
* return the first successful result.
|
|
165
171
|
*/
|
|
166
|
-
export function convertOutput (cid: CID, block: Uint8Array
|
|
172
|
+
export function convertOutput (cid: CID, block: Uint8Array<ArrayBuffer>, accept: AcceptHeader[]): { contentType: ContentType, output: Uint8Array<ArrayBuffer> } {
|
|
167
173
|
if (accept.length === 0) {
|
|
168
174
|
// return current format
|
|
169
175
|
return {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { libp2pDefaults } from '@helia/libp2p'
|
|
1
2
|
import { webRTCDirect } from '@libp2p/webrtc'
|
|
2
3
|
import { webSockets } from '@libp2p/websockets'
|
|
3
|
-
import { libp2pDefaults } from 'helia'
|
|
4
4
|
import type { ServiceFactoryMap } from './libp2p-types.ts'
|
|
5
|
-
import type { DefaultLibp2pServices } from 'helia'
|
|
5
|
+
import type { DefaultLibp2pServices } from '@helia/libp2p'
|
|
6
6
|
import type { Libp2pOptions } from 'libp2p'
|
|
7
7
|
|
|
8
8
|
type ServiceMap = Pick<DefaultLibp2pServices, 'dcutr' | 'identify' | 'keychain' | 'ping'>
|
|
@@ -1,9 +1,7 @@
|
|
|
1
|
+
import { libp2pDefaults } from '@helia/libp2p'
|
|
1
2
|
import { kadDHT } from '@libp2p/kad-dht'
|
|
2
|
-
import { libp2pDefaults } from 'helia'
|
|
3
|
-
import { ipnsSelector } from 'ipns/selector'
|
|
4
|
-
import { ipnsValidator } from 'ipns/validator'
|
|
5
3
|
import type { ServiceFactoryMap } from './libp2p-types.ts'
|
|
6
|
-
import type { DefaultLibp2pServices } from 'helia'
|
|
4
|
+
import type { DefaultLibp2pServices } from '@helia/libp2p'
|
|
7
5
|
import type { Libp2pOptions } from 'libp2p'
|
|
8
6
|
|
|
9
7
|
type ServiceMap = Pick<DefaultLibp2pServices, 'autoNAT' | 'dcutr' | 'dht' | 'identify' | 'keychain' | 'ping' | 'upnp'>
|
|
@@ -17,13 +15,7 @@ export function getLibp2pConfig (): Libp2pOptions & Required<Pick<Libp2pOptions,
|
|
|
17
15
|
autoNAT: libp2pDefaultOptions.services.autoNAT,
|
|
18
16
|
dcutr: libp2pDefaultOptions.services.dcutr,
|
|
19
17
|
dht: kadDHT({
|
|
20
|
-
clientMode: true
|
|
21
|
-
validators: {
|
|
22
|
-
ipns: ipnsValidator
|
|
23
|
-
},
|
|
24
|
-
selectors: {
|
|
25
|
-
ipns: ipnsSelector
|
|
26
|
-
}
|
|
18
|
+
clientMode: true
|
|
27
19
|
}),
|
|
28
20
|
identify: libp2pDefaultOptions.services.identify,
|
|
29
21
|
keychain: libp2pDefaultOptions.services.keychain,
|
package/src/verified-fetch.ts
CHANGED
|
@@ -252,26 +252,26 @@ export class VerifiedFetch {
|
|
|
252
252
|
options?.onProgress?.(evt)
|
|
253
253
|
|
|
254
254
|
if (evt.type === 'helia:routing:find-providers:start') {
|
|
255
|
-
routingTimers[evt.detail.
|
|
255
|
+
routingTimers[evt.detail.router] = {
|
|
256
256
|
start: performance.now(),
|
|
257
257
|
found: 0
|
|
258
258
|
}
|
|
259
259
|
} else if (evt.type === 'helia:routing:find-providers:provider') {
|
|
260
|
-
if (routingTimers[evt.detail.
|
|
260
|
+
if (routingTimers[evt.detail.router] == null) {
|
|
261
261
|
return
|
|
262
262
|
}
|
|
263
263
|
|
|
264
|
-
routingTimers[evt.detail.
|
|
264
|
+
routingTimers[evt.detail.router].found++
|
|
265
265
|
|
|
266
|
-
serverTiming.add(abbreviate('found-provider'), `${abbreviate(evt.detail.
|
|
266
|
+
serverTiming.add(abbreviate('found-provider'), `${abbreviate(evt.detail.router)},${truncate(evt.detail.provider.id)}`, performance.now() - routingTimers[evt.detail.router].start)
|
|
267
267
|
} else if (evt.type === 'helia:routing:find-providers:end') {
|
|
268
|
-
const routing = routingTimers[evt.detail.
|
|
268
|
+
const routing = routingTimers[evt.detail.router]
|
|
269
269
|
|
|
270
270
|
if (routing == null) {
|
|
271
271
|
return
|
|
272
272
|
}
|
|
273
273
|
|
|
274
|
-
serverTiming.add(abbreviate('find-providers'), `${abbreviate(evt.detail.
|
|
274
|
+
serverTiming.add(abbreviate('find-providers'), `${abbreviate(evt.detail.router)},${routing.found}`, performance.now() - routing.start)
|
|
275
275
|
} else if (evt.type === 'helia:block-broker:connect') {
|
|
276
276
|
connectTimers[`connect-${evt.detail.broker}-${evt.detail.provider}`] = {
|
|
277
277
|
start: performance.now(),
|