@helia/verified-fetch 4.1.1 → 5.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.
Files changed (231) hide show
  1. package/README.md +6 -40
  2. package/dist/index.min.js +73 -534
  3. package/dist/index.min.js.map +4 -4
  4. package/dist/src/constants.d.ts +2 -0
  5. package/dist/src/constants.d.ts.map +1 -1
  6. package/dist/src/constants.js +2 -0
  7. package/dist/src/constants.js.map +1 -1
  8. package/dist/src/index.d.ts +162 -68
  9. package/dist/src/index.d.ts.map +1 -1
  10. package/dist/src/index.js +7 -40
  11. package/dist/src/index.js.map +1 -1
  12. package/dist/src/plugins/index.d.ts +0 -5
  13. package/dist/src/plugins/index.d.ts.map +1 -1
  14. package/dist/src/plugins/index.js +0 -4
  15. package/dist/src/plugins/index.js.map +1 -1
  16. package/dist/src/plugins/plugin-base.d.ts +8 -9
  17. package/dist/src/plugins/plugin-base.d.ts.map +1 -1
  18. package/dist/src/plugins/plugin-base.js +5 -6
  19. package/dist/src/plugins/plugin-base.js.map +1 -1
  20. package/dist/src/plugins/plugin-handle-car.d.ts +3 -3
  21. package/dist/src/plugins/plugin-handle-car.d.ts.map +1 -1
  22. package/dist/src/plugins/plugin-handle-car.js +38 -39
  23. package/dist/src/plugins/plugin-handle-car.js.map +1 -1
  24. package/dist/src/plugins/plugin-handle-ipld.d.ts +12 -0
  25. package/dist/src/plugins/plugin-handle-ipld.d.ts.map +1 -0
  26. package/dist/src/plugins/plugin-handle-ipld.js +83 -0
  27. package/dist/src/plugins/plugin-handle-ipld.js.map +1 -0
  28. package/dist/src/plugins/plugin-handle-ipns-record.d.ts +3 -3
  29. package/dist/src/plugins/plugin-handle-ipns-record.d.ts.map +1 -1
  30. package/dist/src/plugins/plugin-handle-ipns-record.js +25 -34
  31. package/dist/src/plugins/plugin-handle-ipns-record.js.map +1 -1
  32. package/dist/src/plugins/plugin-handle-tar.d.ts +3 -3
  33. package/dist/src/plugins/plugin-handle-tar.d.ts.map +1 -1
  34. package/dist/src/plugins/plugin-handle-tar.js +20 -22
  35. package/dist/src/plugins/plugin-handle-tar.js.map +1 -1
  36. package/dist/src/plugins/plugin-handle-unixfs.d.ts +14 -0
  37. package/dist/src/plugins/plugin-handle-unixfs.d.ts.map +1 -0
  38. package/dist/src/plugins/plugin-handle-unixfs.js +180 -0
  39. package/dist/src/plugins/plugin-handle-unixfs.js.map +1 -0
  40. package/dist/src/plugins/types.d.ts +1 -77
  41. package/dist/src/plugins/types.d.ts.map +1 -1
  42. package/dist/src/url-resolver.d.ts +29 -11
  43. package/dist/src/url-resolver.d.ts.map +1 -1
  44. package/dist/src/url-resolver.js +152 -74
  45. package/dist/src/url-resolver.js.map +1 -1
  46. package/dist/src/utils/content-type-parser.d.ts.map +1 -1
  47. package/dist/src/utils/content-type-parser.js +4 -3
  48. package/dist/src/utils/content-type-parser.js.map +1 -1
  49. package/dist/src/utils/content-types.d.ts +26 -0
  50. package/dist/src/utils/content-types.d.ts.map +1 -0
  51. package/dist/src/utils/content-types.js +137 -0
  52. package/dist/src/utils/content-types.js.map +1 -0
  53. package/dist/src/utils/convert-output.d.ts +17 -0
  54. package/dist/src/utils/convert-output.d.ts.map +1 -0
  55. package/dist/src/utils/convert-output.js +176 -0
  56. package/dist/src/utils/convert-output.js.map +1 -0
  57. package/dist/src/utils/error-to-response.d.ts +3 -0
  58. package/dist/src/utils/error-to-response.d.ts.map +1 -0
  59. package/dist/src/utils/error-to-response.js +40 -0
  60. package/dist/src/utils/error-to-response.js.map +1 -0
  61. package/dist/src/utils/get-content-disposition-filename.d.ts +1 -1
  62. package/dist/src/utils/get-content-disposition-filename.d.ts.map +1 -1
  63. package/dist/src/utils/get-content-disposition-filename.js +4 -0
  64. package/dist/src/utils/get-content-disposition-filename.js.map +1 -1
  65. package/dist/src/utils/get-e-tag.d.ts +20 -15
  66. package/dist/src/utils/get-e-tag.d.ts.map +1 -1
  67. package/dist/src/utils/get-e-tag.js +8 -22
  68. package/dist/src/utils/get-e-tag.js.map +1 -1
  69. package/dist/src/utils/get-offset-and-length.d.ts +12 -2
  70. package/dist/src/utils/get-offset-and-length.d.ts.map +1 -1
  71. package/dist/src/utils/get-offset-and-length.js +63 -21
  72. package/dist/src/utils/get-offset-and-length.js.map +1 -1
  73. package/dist/src/utils/get-range-header.d.ts +22 -0
  74. package/dist/src/utils/get-range-header.d.ts.map +1 -0
  75. package/dist/src/utils/get-range-header.js +69 -0
  76. package/dist/src/utils/get-range-header.js.map +1 -0
  77. package/dist/src/utils/parse-url-string.d.ts +2 -1
  78. package/dist/src/utils/parse-url-string.d.ts.map +1 -1
  79. package/dist/src/utils/parse-url-string.js +46 -71
  80. package/dist/src/utils/parse-url-string.js.map +1 -1
  81. package/dist/src/utils/resource-to-cache-key.d.ts +3 -3
  82. package/dist/src/utils/resource-to-cache-key.js +5 -5
  83. package/dist/src/utils/resource-to-cache-key.js.map +1 -1
  84. package/dist/src/utils/response-headers.d.ts +4 -14
  85. package/dist/src/utils/response-headers.d.ts.map +1 -1
  86. package/dist/src/utils/response-headers.js +36 -36
  87. package/dist/src/utils/response-headers.js.map +1 -1
  88. package/dist/src/utils/responses.d.ts +30 -11
  89. package/dist/src/utils/responses.d.ts.map +1 -1
  90. package/dist/src/utils/responses.js +146 -39
  91. package/dist/src/utils/responses.js.map +1 -1
  92. package/dist/src/verified-fetch.d.ts +16 -15
  93. package/dist/src/verified-fetch.d.ts.map +1 -1
  94. package/dist/src/verified-fetch.js +302 -238
  95. package/dist/src/verified-fetch.js.map +1 -1
  96. package/dist/typedoc-urls.json +64 -45
  97. package/package.json +4 -3
  98. package/src/constants.ts +3 -0
  99. package/src/index.ts +199 -68
  100. package/src/plugins/index.ts +0 -6
  101. package/src/plugins/plugin-base.ts +8 -10
  102. package/src/plugins/plugin-handle-car.ts +48 -46
  103. package/src/plugins/plugin-handle-ipld.ts +93 -0
  104. package/src/plugins/plugin-handle-ipns-record.ts +31 -41
  105. package/src/plugins/plugin-handle-tar.ts +25 -29
  106. package/src/plugins/plugin-handle-unixfs.ts +217 -0
  107. package/src/plugins/types.ts +0 -86
  108. package/src/url-resolver.ts +197 -83
  109. package/src/utils/content-type-parser.ts +4 -3
  110. package/src/utils/content-types.ts +159 -0
  111. package/src/utils/convert-output.ts +187 -0
  112. package/src/utils/error-to-response.ts +49 -0
  113. package/src/utils/get-content-disposition-filename.ts +7 -1
  114. package/src/utils/get-e-tag.ts +26 -35
  115. package/src/utils/get-offset-and-length.ts +75 -21
  116. package/src/utils/get-range-header.ts +107 -0
  117. package/src/utils/parse-url-string.ts +51 -80
  118. package/src/utils/resource-to-cache-key.ts +5 -5
  119. package/src/utils/response-headers.ts +40 -41
  120. package/src/utils/responses.ts +186 -45
  121. package/src/verified-fetch.ts +353 -270
  122. package/dist/src/plugins/plugin-handle-byte-range-context.d.ts +0 -14
  123. package/dist/src/plugins/plugin-handle-byte-range-context.d.ts.map +0 -1
  124. package/dist/src/plugins/plugin-handle-byte-range-context.js +0 -25
  125. package/dist/src/plugins/plugin-handle-byte-range-context.js.map +0 -1
  126. package/dist/src/plugins/plugin-handle-cbor.d.ts +0 -17
  127. package/dist/src/plugins/plugin-handle-cbor.d.ts.map +0 -1
  128. package/dist/src/plugins/plugin-handle-cbor.js +0 -94
  129. package/dist/src/plugins/plugin-handle-cbor.js.map +0 -1
  130. package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.d.ts +0 -27
  131. package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.d.ts.map +0 -1
  132. package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.js +0 -279
  133. package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.js.map +0 -1
  134. package/dist/src/plugins/plugin-handle-dag-cbor.d.ts +0 -17
  135. package/dist/src/plugins/plugin-handle-dag-cbor.d.ts.map +0 -1
  136. package/dist/src/plugins/plugin-handle-dag-cbor.js +0 -66
  137. package/dist/src/plugins/plugin-handle-dag-cbor.js.map +0 -1
  138. package/dist/src/plugins/plugin-handle-dag-pb.d.ts +0 -17
  139. package/dist/src/plugins/plugin-handle-dag-pb.d.ts.map +0 -1
  140. package/dist/src/plugins/plugin-handle-dag-pb.js +0 -209
  141. package/dist/src/plugins/plugin-handle-dag-pb.js.map +0 -1
  142. package/dist/src/plugins/plugin-handle-dag-walk.d.ts +0 -21
  143. package/dist/src/plugins/plugin-handle-dag-walk.d.ts.map +0 -1
  144. package/dist/src/plugins/plugin-handle-dag-walk.js +0 -95
  145. package/dist/src/plugins/plugin-handle-dag-walk.js.map +0 -1
  146. package/dist/src/plugins/plugin-handle-dir-index-html.d.ts +0 -10
  147. package/dist/src/plugins/plugin-handle-dir-index-html.d.ts.map +0 -1
  148. package/dist/src/plugins/plugin-handle-dir-index-html.js +0 -59
  149. package/dist/src/plugins/plugin-handle-dir-index-html.js.map +0 -1
  150. package/dist/src/plugins/plugin-handle-json.d.ts +0 -12
  151. package/dist/src/plugins/plugin-handle-json.d.ts.map +0 -1
  152. package/dist/src/plugins/plugin-handle-json.js +0 -73
  153. package/dist/src/plugins/plugin-handle-json.js.map +0 -1
  154. package/dist/src/plugins/plugin-handle-raw.d.ts +0 -9
  155. package/dist/src/plugins/plugin-handle-raw.d.ts.map +0 -1
  156. package/dist/src/plugins/plugin-handle-raw.js +0 -92
  157. package/dist/src/plugins/plugin-handle-raw.js.map +0 -1
  158. package/dist/src/plugins/plugins.d.ts +0 -6
  159. package/dist/src/plugins/plugins.d.ts.map +0 -1
  160. package/dist/src/plugins/plugins.js +0 -6
  161. package/dist/src/plugins/plugins.js.map +0 -1
  162. package/dist/src/utils/byte-range-context.d.ts +0 -103
  163. package/dist/src/utils/byte-range-context.d.ts.map +0 -1
  164. package/dist/src/utils/byte-range-context.js +0 -504
  165. package/dist/src/utils/byte-range-context.js.map +0 -1
  166. package/dist/src/utils/dag-cbor-to-safe-json.d.ts +0 -15
  167. package/dist/src/utils/dag-cbor-to-safe-json.d.ts.map +0 -1
  168. package/dist/src/utils/dag-cbor-to-safe-json.js +0 -54
  169. package/dist/src/utils/dag-cbor-to-safe-json.js.map +0 -1
  170. package/dist/src/utils/dir-index-html.d.ts +0 -19
  171. package/dist/src/utils/dir-index-html.d.ts.map +0 -1
  172. package/dist/src/utils/dir-index-html.js +0 -438
  173. package/dist/src/utils/dir-index-html.js.map +0 -1
  174. package/dist/src/utils/get-peer-id-from-string.d.ts +0 -3
  175. package/dist/src/utils/get-peer-id-from-string.d.ts.map +0 -1
  176. package/dist/src/utils/get-peer-id-from-string.js +0 -10
  177. package/dist/src/utils/get-peer-id-from-string.js.map +0 -1
  178. package/dist/src/utils/get-resolved-accept-header.d.ts +0 -9
  179. package/dist/src/utils/get-resolved-accept-header.d.ts.map +0 -1
  180. package/dist/src/utils/get-resolved-accept-header.js +0 -27
  181. package/dist/src/utils/get-resolved-accept-header.js.map +0 -1
  182. package/dist/src/utils/get-stream-from-async-iterable.d.ts +0 -9
  183. package/dist/src/utils/get-stream-from-async-iterable.d.ts.map +0 -1
  184. package/dist/src/utils/get-stream-from-async-iterable.js +0 -43
  185. package/dist/src/utils/get-stream-from-async-iterable.js.map +0 -1
  186. package/dist/src/utils/handle-redirects.d.ts +0 -16
  187. package/dist/src/utils/handle-redirects.d.ts.map +0 -1
  188. package/dist/src/utils/handle-redirects.js +0 -84
  189. package/dist/src/utils/handle-redirects.js.map +0 -1
  190. package/dist/src/utils/is-accept-explicit.d.ts +0 -15
  191. package/dist/src/utils/is-accept-explicit.d.ts.map +0 -1
  192. package/dist/src/utils/is-accept-explicit.js +0 -26
  193. package/dist/src/utils/is-accept-explicit.js.map +0 -1
  194. package/dist/src/utils/request-headers.d.ts +0 -13
  195. package/dist/src/utils/request-headers.d.ts.map +0 -1
  196. package/dist/src/utils/request-headers.js +0 -63
  197. package/dist/src/utils/request-headers.js.map +0 -1
  198. package/dist/src/utils/select-output-type.d.ts +0 -17
  199. package/dist/src/utils/select-output-type.d.ts.map +0 -1
  200. package/dist/src/utils/select-output-type.js +0 -153
  201. package/dist/src/utils/select-output-type.js.map +0 -1
  202. package/dist/src/utils/tlru.d.ts +0 -15
  203. package/dist/src/utils/tlru.d.ts.map +0 -1
  204. package/dist/src/utils/tlru.js +0 -34
  205. package/dist/src/utils/tlru.js.map +0 -1
  206. package/dist/src/utils/walk-path.d.ts +0 -27
  207. package/dist/src/utils/walk-path.d.ts.map +0 -1
  208. package/dist/src/utils/walk-path.js +0 -45
  209. package/dist/src/utils/walk-path.js.map +0 -1
  210. package/src/plugins/plugin-handle-byte-range-context.ts +0 -30
  211. package/src/plugins/plugin-handle-cbor.ts +0 -107
  212. package/src/plugins/plugin-handle-dag-cbor-html-preview.ts +0 -295
  213. package/src/plugins/plugin-handle-dag-cbor.ts +0 -83
  214. package/src/plugins/plugin-handle-dag-pb.ts +0 -248
  215. package/src/plugins/plugin-handle-dag-walk.ts +0 -110
  216. package/src/plugins/plugin-handle-dir-index-html.ts +0 -72
  217. package/src/plugins/plugin-handle-json.ts +0 -80
  218. package/src/plugins/plugin-handle-raw.ts +0 -110
  219. package/src/plugins/plugins.ts +0 -5
  220. package/src/utils/byte-range-context.ts +0 -597
  221. package/src/utils/dag-cbor-to-safe-json.ts +0 -63
  222. package/src/utils/dir-index-html.ts +0 -505
  223. package/src/utils/get-peer-id-from-string.ts +0 -12
  224. package/src/utils/get-resolved-accept-header.ts +0 -42
  225. package/src/utils/get-stream-from-async-iterable.ts +0 -49
  226. package/src/utils/handle-redirects.ts +0 -109
  227. package/src/utils/is-accept-explicit.ts +0 -38
  228. package/src/utils/request-headers.ts +0 -65
  229. package/src/utils/select-output-type.ts +0 -175
  230. package/src/utils/tlru.ts +0 -42
  231. package/src/utils/walk-path.ts +0 -69
@@ -1,109 +0,0 @@
1
- import { SubdomainNotSupportedError } from '../errors.js'
2
- import { parseURLString } from './parse-url-string.js'
3
- import { movedPermanentlyResponse } from './responses.js'
4
- import type { VerifiedFetchInit, Resource } from '../index.js'
5
- import type { AbortOptions, ComponentLogger } from '@libp2p/interface'
6
- import type { CID } from 'multiformats/cid'
7
-
8
- interface GetRedirectResponse {
9
- cid: CID
10
- resource: Resource
11
- options?: Omit<VerifiedFetchInit, 'signal'> & AbortOptions
12
- logger: ComponentLogger
13
-
14
- /**
15
- * Only used in testing.
16
- */
17
- fetch?: typeof globalThis.fetch
18
- }
19
-
20
- function maybeAddTrailingSlash (path: string): string {
21
- // if it has an extension-like ending, don't add a trailing slash
22
- if (path.match(/\.[a-zA-Z0-9]{1,4}$/) != null) {
23
- return path
24
- }
25
- return path.endsWith('/') ? path : `${path}/`
26
- }
27
-
28
- // See https://specs.ipfs.tech/http-gateways/path-gateway/#location-response-header
29
- export async function getRedirectResponse ({ resource, options, logger, cid, fetch = globalThis.fetch }: GetRedirectResponse): Promise<null | Response> {
30
- const log = logger.forComponent('helia:verified-fetch:get-redirect-response')
31
-
32
- if (typeof resource !== 'string' || options == null || ['ipfs://', 'ipns://'].some((prefix) => resource.startsWith(prefix))) {
33
- return null
34
- }
35
-
36
- const headers = new Headers(options?.headers)
37
- const forwardedHost = headers.get('x-forwarded-host')
38
- const headerHost = headers.get('host')
39
- const forwardedFor = headers.get('x-forwarded-for')
40
-
41
- if (forwardedFor == null && forwardedHost == null && headerHost == null) {
42
- log.trace('no redirect info found in headers')
43
- return null
44
- }
45
-
46
- log.trace('checking for redirect info')
47
- // if x-forwarded-host is passed, we need to set the location header to the
48
- // subdomain so that the browser can redirect to the correct subdomain
49
- try {
50
- const urlParts = parseURLString(resource)
51
- const reqUrl = new URL(resource)
52
- const actualHost = forwardedHost ?? reqUrl.host
53
- const subdomainUrl = new URL(reqUrl)
54
-
55
- if (urlParts.protocol === 'ipfs' && cid.version === 0) {
56
- subdomainUrl.host = `${cid.toV1()}.ipfs.${actualHost}`
57
- } else {
58
- subdomainUrl.host = `${urlParts.cidOrPeerIdOrDnsLink}.${urlParts.protocol}.${actualHost}`
59
- }
60
-
61
- if (headerHost?.includes(urlParts.protocol) === true && subdomainUrl.host.includes(headerHost)) {
62
- log.trace('request was for a subdomain already, not setting location header')
63
- return null
64
- }
65
-
66
- if (headerHost != null && !subdomainUrl.host.includes(headerHost)) {
67
- log.trace('host header is not the same as the subdomain url host, not setting location header')
68
- return null
69
- }
70
-
71
- if (reqUrl.host === subdomainUrl.host) {
72
- log.trace('req url is the same as the subdomain url, not setting location header')
73
- return null
74
- }
75
-
76
- subdomainUrl.pathname = maybeAddTrailingSlash(reqUrl.pathname.replace(`/${urlParts.cidOrPeerIdOrDnsLink}`, '').replace(`/${urlParts.protocol}`, ''))
77
- log.trace('subdomain url %s', subdomainUrl.href)
78
- const pathUrl = new URL(reqUrl, `${reqUrl.protocol}//${actualHost}`)
79
- pathUrl.pathname = maybeAddTrailingSlash(reqUrl.pathname)
80
- log.trace('path url %s', pathUrl.href)
81
-
82
- // try to query subdomain with HEAD request to see if it's supported
83
- try {
84
- const subdomainTest = await fetch(subdomainUrl, { method: 'HEAD' })
85
- if (subdomainTest.ok) {
86
- log('subdomain supported, redirecting to subdomain')
87
- return movedPermanentlyResponse(resource.toString(), subdomainUrl.href)
88
- } else {
89
- log('subdomain not supported, subdomain failed with status %s %s', subdomainTest.status, subdomainTest.statusText)
90
- throw new SubdomainNotSupportedError('subdomain not supported')
91
- }
92
- } catch (err: any) {
93
- log('subdomain not supported - %e', err)
94
-
95
- if (pathUrl.href === reqUrl.href) {
96
- log('path url is the same as the request url, not setting location header')
97
-
98
- return null
99
- }
100
-
101
- // pathUrl is different from request URL (maybe even with just a trailing slash)
102
- return movedPermanentlyResponse(resource.toString(), pathUrl.href)
103
- }
104
- } catch (e) {
105
- // if it's not a full URL, we have nothing left to do.
106
- log.error('error setting location header for x-forwarded-host', e)
107
- }
108
- return null
109
- }
@@ -1,38 +0,0 @@
1
- import { FORMAT_TO_MIME_TYPE } from './select-output-type.js'
2
- import type { UrlQuery } from '../index.ts'
3
-
4
- export interface IsAcceptExplicitOptions {
5
- query?: UrlQuery
6
- headers: Headers
7
- }
8
-
9
- export function isExplicitAcceptHeader (headers: Headers): boolean {
10
- const incomingAcceptHeader = headers.get('accept')
11
-
12
- if (incomingAcceptHeader == null) {
13
- return false
14
- }
15
-
16
- return Object.values(FORMAT_TO_MIME_TYPE)
17
- .some(mimeType => incomingAcceptHeader.includes(mimeType))
18
- }
19
-
20
- export function isExplicitFormatQuery (query?: UrlQuery): boolean {
21
- const formatQuery = query?.format
22
-
23
- if (formatQuery != null && Object.keys(FORMAT_TO_MIME_TYPE).includes(formatQuery)) {
24
- return true
25
- }
26
-
27
- return false
28
- }
29
-
30
- /**
31
- * The user can provide an explicit `accept` header in the request headers or a
32
- * `format` query parameter in the URL.
33
- *
34
- * If either of these are provided, this function returns true.
35
- */
36
- export function isExplicitIpldAcceptRequest ({ query, headers }: IsAcceptExplicitOptions): boolean {
37
- return isExplicitAcceptHeader(headers) || isExplicitFormatQuery(query)
38
- }
@@ -1,65 +0,0 @@
1
- import { InvalidRangeError } from '../errors.js'
2
-
3
- export function getHeader (headers: HeadersInit | undefined, header: string): string | undefined {
4
- if (headers == null) {
5
- return undefined
6
- }
7
- if (headers instanceof Headers) {
8
- return headers.get(header) ?? undefined
9
- }
10
- if (Array.isArray(headers)) {
11
- const entry = headers.find(([key]) => key.toLowerCase() === header.toLowerCase())
12
- return entry?.[1]
13
- }
14
- const key = Object.keys(headers).find(k => k.toLowerCase() === header.toLowerCase())
15
- if (key == null) {
16
- return undefined
17
- }
18
-
19
- return headers[key]
20
- }
21
-
22
- /**
23
- * Given two ints from a Range header, and potential fileSize, returns:
24
- * 1. number of bytes the response should contain.
25
- * 2. the start index of the range. // inclusive
26
- * 3. the end index of the range. // inclusive
27
- */
28
- // eslint-disable-next-line complexity
29
- export function calculateByteRangeIndexes (start: number | undefined, end: number | undefined, fileSize?: number): { byteSize?: number, start?: number, end?: number } {
30
- if ((start ?? 0) > (end ?? Infinity)) {
31
- throw new InvalidRangeError('Invalid range: Range-start index is greater than range-end index.')
32
- }
33
- if (start != null && (end ?? 0) >= (fileSize ?? Infinity)) {
34
- throw new InvalidRangeError('Invalid range: Range-end index is greater than or equal to the size of the file.')
35
- }
36
- if (start == null && (end ?? 0) > (fileSize ?? Infinity)) {
37
- throw new InvalidRangeError('Invalid range: Range-end index is greater than the size of the file.')
38
- }
39
- if (start != null && start < 0) {
40
- throw new InvalidRangeError('Invalid range: Range-start index cannot be negative.')
41
- }
42
-
43
- if (start != null && end != null) {
44
- return { byteSize: end - start + 1, start, end }
45
- } else if (start == null && end != null) {
46
- // suffix byte range requested
47
- if (fileSize == null) {
48
- return { end }
49
- }
50
- if (end === fileSize) {
51
- return { byteSize: fileSize, start: 0, end: fileSize - 1 }
52
- }
53
- return { byteSize: end, start: fileSize - end, end: fileSize - 1 }
54
- } else if (start != null && end == null) {
55
- if (fileSize == null) {
56
- // we only have the start index, and no fileSize, so we can't return a valid range.
57
- return { start }
58
- }
59
- const end = fileSize - 1
60
- const byteSize = fileSize - start
61
- return { byteSize, start, end }
62
- }
63
-
64
- return { byteSize: fileSize, start: 0, end: fileSize != null ? fileSize - 1 : 0 }
65
- }
@@ -1,175 +0,0 @@
1
- import { code as dagCborCode } from '@ipld/dag-cbor'
2
- import { code as dagJsonCode } from '@ipld/dag-json'
3
- import { code as dagPbCode } from '@ipld/dag-pb'
4
- import { code as jsonCode } from 'multiformats/codecs/json'
5
- import { code as rawCode } from 'multiformats/codecs/raw'
6
- import { CODEC_CBOR } from '../constants.ts'
7
- import type { RequestFormatShorthand } from '../index.js'
8
- import type { CID } from 'multiformats/cid'
9
-
10
- /**
11
- * This maps supported response types for each codec supported by verified-fetch
12
- */
13
- const CID_TYPE_MAP: Record<number, string[]> = {
14
- [dagCborCode]: [
15
- 'application/json',
16
- 'application/vnd.ipld.dag-cbor',
17
- 'application/cbor',
18
- 'application/vnd.ipld.dag-json',
19
- 'application/octet-stream',
20
- 'application/vnd.ipld.raw',
21
- 'application/vnd.ipfs.ipns-record',
22
- 'application/vnd.ipld.car',
23
- 'text/html'
24
- ],
25
- [dagJsonCode]: [
26
- 'application/json',
27
- 'application/vnd.ipld.dag-cbor',
28
- 'application/cbor',
29
- 'application/vnd.ipld.dag-json',
30
- 'application/octet-stream',
31
- 'application/vnd.ipld.raw',
32
- 'application/vnd.ipfs.ipns-record',
33
- 'application/vnd.ipld.car'
34
- ],
35
- [jsonCode]: [
36
- 'application/json',
37
- 'application/vnd.ipld.dag-cbor',
38
- 'application/cbor',
39
- 'application/vnd.ipld.dag-json',
40
- 'application/octet-stream',
41
- 'application/vnd.ipld.raw',
42
- 'application/vnd.ipfs.ipns-record',
43
- 'application/vnd.ipld.car'
44
- ],
45
- [dagPbCode]: [
46
- 'application/octet-stream',
47
- 'application/json',
48
- 'application/vnd.ipld.dag-cbor',
49
- 'application/cbor',
50
- 'application/vnd.ipld.dag-json',
51
- 'application/vnd.ipld.raw',
52
- 'application/vnd.ipfs.ipns-record',
53
- 'application/vnd.ipld.car',
54
- 'application/x-tar'
55
- ],
56
- [rawCode]: [
57
- 'application/octet-stream',
58
- 'application/vnd.ipld.raw',
59
- 'application/vnd.ipfs.ipns-record',
60
- 'application/vnd.ipld.dag-json',
61
- 'application/vnd.ipld.car',
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'
74
- ]
75
- }
76
-
77
- export interface AcceptHeader {
78
- mimeType: string
79
- options: Record<string, string>
80
- }
81
-
82
- /**
83
- * Selects an output mime-type based on the CID and a passed `Accept` header
84
- */
85
- export function selectOutputType (cid: CID, accept?: string): AcceptHeader | undefined {
86
- const cidMimeTypes = CID_TYPE_MAP[cid.code] ?? []
87
-
88
- if (accept != null) {
89
- return chooseMimeType(accept, cidMimeTypes)
90
- }
91
- }
92
-
93
- function chooseMimeType (accept: string, validMimeTypes: string[]): AcceptHeader | undefined {
94
- const requestedMimeTypes = accept
95
- .split(',')
96
- .map(s => {
97
- const parts = s.trim().split(';')
98
-
99
- const options: Record<string, string> = {
100
- q: '0'
101
- }
102
-
103
- for (let i = 1; i < parts.length; i++) {
104
- const [key, value] = parts[i].split('=').map(s => s.trim())
105
-
106
- options[key] = value
107
- }
108
-
109
- return {
110
- mimeType: `${parts[0]}`.trim(),
111
- options
112
- }
113
- })
114
- .sort((a, b) => {
115
- if (a.options.q === b.options.q) {
116
- return 0
117
- }
118
-
119
- if (a.options.q > b.options.q) {
120
- return -1
121
- }
122
-
123
- return 1
124
- })
125
-
126
- for (const headerFormat of requestedMimeTypes) {
127
- for (const mimeType of validMimeTypes) {
128
- if (headerFormat.mimeType.includes(mimeType)) {
129
- return headerFormat
130
- }
131
-
132
- if (headerFormat.mimeType === '*/*') {
133
- return {
134
- mimeType,
135
- options: headerFormat.options
136
- }
137
- }
138
-
139
- if (headerFormat.mimeType.startsWith('*/') && mimeType.split('/')[1] === headerFormat.mimeType.split('/')[1]) {
140
- return {
141
- mimeType,
142
- options: headerFormat.options
143
- }
144
- }
145
-
146
- if (headerFormat.mimeType.endsWith('/*') && mimeType.split('/')[0] === headerFormat.mimeType.split('/')[0]) {
147
- return {
148
- mimeType,
149
- options: headerFormat.options
150
- }
151
- }
152
- }
153
- }
154
- }
155
-
156
- export const FORMAT_TO_MIME_TYPE: Record<RequestFormatShorthand, string> = {
157
- raw: 'application/vnd.ipld.raw',
158
- car: 'application/vnd.ipld.car',
159
- 'dag-json': 'application/vnd.ipld.dag-json',
160
- 'dag-cbor': 'application/vnd.ipld.dag-cbor',
161
- json: 'application/json',
162
- cbor: 'application/cbor',
163
- 'ipns-record': 'application/vnd.ipfs.ipns-record',
164
- tar: 'application/x-tar'
165
- }
166
-
167
- /**
168
- * Converts a `format=...` query param to a mime type as would be found in the
169
- * `Accept` header, if a valid mapping is available
170
- */
171
- export function queryFormatToAcceptHeader (format?: RequestFormatShorthand): string | undefined {
172
- if (format != null) {
173
- return FORMAT_TO_MIME_TYPE[format]
174
- }
175
- }
package/src/utils/tlru.ts DELETED
@@ -1,42 +0,0 @@
1
- import QuickLRU from 'quick-lru'
2
-
3
- /**
4
- * Time Aware Least Recent Used Cache
5
- *
6
- * @see https://arxiv.org/pdf/1801.00390
7
- */
8
- export class TLRU<T> {
9
- private readonly lru: QuickLRU<string, T>
10
-
11
- constructor (maxSize: number) {
12
- this.lru = new QuickLRU({ maxSize })
13
- }
14
-
15
- get (key: string): T | undefined {
16
- return this.lru.get(key)
17
- }
18
-
19
- set (key: string, value: T, ttlMs: number): void {
20
- this.lru.set(key, value, {
21
- maxAge: Date.now() + ttlMs
22
- })
23
- }
24
-
25
- has (key: string): boolean {
26
- const value = this.get(key)
27
-
28
- if (value != null) {
29
- return true
30
- }
31
-
32
- return false
33
- }
34
-
35
- remove (key: string): void {
36
- this.lru.delete(key)
37
- }
38
-
39
- clear (): void {
40
- this.lru.clear()
41
- }
42
- }
@@ -1,69 +0,0 @@
1
- import { DoesNotExistError } from '@helia/unixfs/errors'
2
- import { AbortError } from '@libp2p/interface'
3
- import { walkPath as exporterWalk } from 'ipfs-unixfs-exporter'
4
- import { badGatewayResponse, notFoundResponse } from './responses.js'
5
- import type { PluginContext } from '../plugins/types.js'
6
- import type { Logger } from '@libp2p/interface'
7
- import type { Blockstore } from 'interface-blockstore'
8
- import type { ExporterOptions, ReadableStorage, ObjectNode, UnixFSEntry } from 'ipfs-unixfs-exporter'
9
- import type { CID } from 'multiformats/cid'
10
-
11
- export interface PathWalkerOptions extends ExporterOptions {
12
-
13
- }
14
-
15
- export interface PathWalkerResponse {
16
- ipfsRoots: CID[]
17
- terminalElement: UnixFSEntry
18
- }
19
-
20
- export interface PathWalkerFn {
21
- (blockstore: ReadableStorage, path: string, options?: PathWalkerOptions): Promise<PathWalkerResponse>
22
- }
23
-
24
- async function walkPath (blockstore: ReadableStorage, path: string, options?: PathWalkerOptions): Promise<PathWalkerResponse> {
25
- const ipfsRoots: CID[] = []
26
- let terminalElement: UnixFSEntry | undefined
27
-
28
- for await (const entry of exporterWalk(path, blockstore, options)) {
29
- ipfsRoots.push(entry.cid)
30
- terminalElement = entry
31
- }
32
-
33
- if (terminalElement == null) {
34
- throw new DoesNotExistError('No terminal element found')
35
- }
36
-
37
- return {
38
- ipfsRoots,
39
- terminalElement
40
- }
41
- }
42
-
43
- export function isObjectNode (node: UnixFSEntry): node is ObjectNode {
44
- return node.type === 'object'
45
- }
46
-
47
- /**
48
- * Attempts to walk the path in the blockstore, returning ipfsRoots needed to resolve the path, and the terminal element.
49
- * If the signal is aborted, the function will throw an AbortError
50
- * If a terminal element is not found, a notFoundResponse is returned
51
- * If another unknown error occurs, a badGatewayResponse is returned
52
- *
53
- */
54
- export async function handlePathWalking ({ cid, path, resource, options, blockstore, log }: PluginContext & { blockstore: Blockstore, log: Logger }): Promise<PathWalkerResponse | Response> {
55
- try {
56
- return await walkPath(blockstore, `${cid}/${path.join('/')}`, options)
57
- } catch (err: any) {
58
- if (options?.signal?.aborted) {
59
- throw new AbortError(options?.signal?.reason)
60
- }
61
-
62
- if (['ERR_NO_PROP', 'ERR_NO_TERMINAL_ELEMENT', 'ERR_NOT_FOUND'].includes(err.code)) {
63
- return notFoundResponse(resource)
64
- }
65
-
66
- log.error('error walking path "%s" - %e', path, err)
67
- return badGatewayResponse(resource, 'Error walking path')
68
- }
69
- }