@helia/verified-fetch 4.1.1 → 5.0.0

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
@@ -0,0 +1,107 @@
1
+ import { InvalidRangeError } from '../errors.ts'
2
+ import { badRequestResponse, notSatisfiableResponse } from './responses.ts'
3
+
4
+ /**
5
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Range
6
+ */
7
+ export interface Range {
8
+ /**
9
+ * Where the range starts, zero indexed
10
+ */
11
+ start?: number
12
+
13
+ /**
14
+ * Where the range ends, inclusive
15
+ */
16
+ end?: number
17
+ }
18
+
19
+ /**
20
+ * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Range
21
+ */
22
+ export interface RangeHeader {
23
+ multipartBoundary: string
24
+ ranges: Range[]
25
+ }
26
+
27
+ function parseValue (val?: string): number | undefined {
28
+ if (val == null || val === '') {
29
+ return
30
+ }
31
+
32
+ const num = Number(val)
33
+
34
+ if (isNaN(num)) {
35
+ throw new InvalidRangeError(`Invalid range specification: could not parse "${num}" as number`)
36
+ }
37
+
38
+ return num
39
+ }
40
+
41
+ function getByteRangeFromHeader (rangeHeader?: string): Range[] {
42
+ if (rangeHeader == null || rangeHeader === '') {
43
+ return []
44
+ }
45
+
46
+ /**
47
+ * Range: bytes=<start>-<end> | bytes=<start2>- | bytes=-<end2> | bytes=<start1>-<end1>,<start2>-<end2>,...
48
+ */
49
+ if (!rangeHeader.startsWith('bytes=')) {
50
+ throw new InvalidRangeError('Invalid range request')
51
+ }
52
+
53
+ const rangesStr = rangeHeader.substring(6) // Remove "bytes=" prefix
54
+ const rangeParts = rangesStr.split(',').map(part => part.trim())
55
+ const ranges: Range[] = []
56
+
57
+ for (const part of rangeParts) {
58
+ const match = part.match(/^(?<start>\d+)?-(?<end>\d+)?$/)
59
+
60
+ if (match?.groups == null) {
61
+ throw new InvalidRangeError(`Invalid range specification: ${part}`)
62
+ }
63
+
64
+ if (part.startsWith('-')) {
65
+ ranges.push({
66
+ end: parseValue(part)
67
+ })
68
+ } else {
69
+ const { start, end } = match.groups
70
+
71
+ ranges.push({
72
+ start: parseValue(start),
73
+ end: parseValue(end)
74
+ })
75
+ }
76
+ }
77
+
78
+ return ranges
79
+ }
80
+
81
+ export function getRangeHeader (resource: string, headers: Headers): RangeHeader | undefined | Response {
82
+ const header = headers.get('range')
83
+
84
+ // not a range request
85
+ if (header == null) {
86
+ return
87
+ }
88
+
89
+ try {
90
+ const ranges = getByteRangeFromHeader(header)
91
+
92
+ if (ranges.length === 0) {
93
+ return
94
+ }
95
+
96
+ return {
97
+ multipartBoundary: `multipart_byteranges_${Math.floor(Math.random() * 1_000_000_000)}`,
98
+ ranges
99
+ }
100
+ } catch (e: any) {
101
+ if (e.name === 'InvalidRangeError') {
102
+ return notSatisfiableResponse(resource)
103
+ }
104
+
105
+ return badRequestResponse(resource, e)
106
+ }
107
+ }
@@ -1,4 +1,6 @@
1
1
  import { InvalidParametersError } from '@libp2p/interface'
2
+ import { peerIdFromCID, peerIdFromString } from '@libp2p/peer-id'
3
+ import { CID } from 'multiformats/cid'
2
4
  import { decodeDNSLinkLabel, isInlinedDnsLink } from './dnslink-label.ts'
3
5
  import { ipfsPathToUrl, ipfsUrlToUrl } from './ipfs-path-to-url.ts'
4
6
 
@@ -7,7 +9,8 @@ interface SubdomainMatchGroups {
7
9
  cidOrPeerIdOrDnsLink: string
8
10
  }
9
11
 
10
- const SUBDOMAIN_GATEWAY_REGEX = /^(?<cidOrPeerIdOrDnsLink>[^/?]+)\.(?<protocol>ip[fn]s)\.([^/?]+)$/
12
+ export const SUBDOMAIN_GATEWAY_REGEX = /^(?<cidOrPeerIdOrDnsLink>[^/?]+)\.(?<protocol>ip[fn]s)\.([^/?]+)$/
13
+ const CODEC_LIBP2P_KEY = 0x72
11
14
 
12
15
  function matchSubdomainGroupsGuard (groups?: null | { [key in string]: string; } | SubdomainMatchGroups): groups is SubdomainMatchGroups {
13
16
  const protocol = groups?.protocol
@@ -34,40 +37,6 @@ export interface ParsedURL {
34
37
  fragment: string
35
38
  }
36
39
 
37
- function toQuery (query?: URLSearchParams): Record<string, any> {
38
- if (query == null) {
39
- return {}
40
- }
41
-
42
- const output: Record<string, any> = {}
43
-
44
- for (const [key, value] of query.entries()) {
45
- output[key] = value
46
-
47
- if (value === 'true') {
48
- output[key] = true
49
- }
50
-
51
- if (value === 'false') {
52
- output[key] = false
53
- }
54
- }
55
-
56
- return output
57
- }
58
-
59
- function stripLeadingHash (pathname: string): string {
60
- return stripLeading(pathname, '#')
61
- }
62
-
63
- function stripLeading (str: string, char: string): string {
64
- while (str.startsWith(char)) {
65
- str = str.substring(1)
66
- }
67
-
68
- return str
69
- }
70
-
71
40
  /**
72
41
  * If the caller has passed a case-sensitive identifier (like a base58btc
73
42
  * encoded CID or PeerId) in a case-insensitive location (like a subdomain),
@@ -83,7 +52,11 @@ function findOriginalCidOrPeer (needle: string, haystack: string): string {
83
52
  return haystack.substring(start, start + needle.length)
84
53
  }
85
54
 
86
- function toUrl (urlString: string): URL {
55
+ function stringToUrl (urlString: string | URL): URL {
56
+ if (urlString instanceof URL) {
57
+ return urlString
58
+ }
59
+
87
60
  // turn IPFS/IPNS path into gateway URL string
88
61
  if (urlString.startsWith('/ipfs/') || urlString.startsWith('/ipns/')) {
89
62
  urlString = ipfsPathToUrl(urlString)
@@ -101,21 +74,9 @@ function toUrl (urlString: string): URL {
101
74
  throw new InvalidParametersError(`Invalid URL: ${urlString}`)
102
75
  }
103
76
 
104
- /**
105
- * Accepts the following url strings:
106
- *
107
- * - /ipfs/Qmfoo/path
108
- * - /ipns/Qmfoo/path
109
- * - ipfs://cid/path
110
- * - ipns://name/path
111
- * - http://cid.ipfs.example.com/path
112
- * - http://name.ipns.example.com/path
113
- * - http://example.com/ipfs/cid/path
114
- * - http://example.com/ipns/name/path
115
- */
116
- export function parseURLString (urlString: string): ParsedURL {
77
+ function toURL (urlString: string): URL {
117
78
  // validate url
118
- const url = toUrl(urlString)
79
+ const url = stringToUrl(urlString)
119
80
 
120
81
  // test for subdomain gateway URL
121
82
  const subdomainMatch = url.hostname.match(SUBDOMAIN_GATEWAY_REGEX)
@@ -136,16 +97,7 @@ export function parseURLString (urlString: string): ParsedURL {
136
97
  // input while also maintaining a sane canonical URL for the resource. Phew.
137
98
  const wat = new URL(`not-${urlString}`)
138
99
 
139
- return {
140
- url: new URL(`${groups.protocol}://${cidOrPeerIdOrDnsLink}${wat.pathname}${url.search}${url.hash}`),
141
- protocol: groups.protocol,
142
- cidOrPeerIdOrDnsLink,
143
- path: url.pathname.split('/')
144
- .filter(str => str !== '')
145
- .map(str => decodeURIComponent(str)),
146
- query: toQuery(url.searchParams),
147
- fragment: stripLeadingHash(url.hash)
148
- }
100
+ return new URL(`${groups.protocol}://${cidOrPeerIdOrDnsLink}${wat.pathname}${url.search}${url.hash}`)
149
101
  }
150
102
 
151
103
  // test for IPFS path gateway URL
@@ -157,16 +109,7 @@ export function parseURLString (urlString: string): ParsedURL {
157
109
  throw new InvalidParametersError(`Path gateway URL ${urlString} had no CID`)
158
110
  }
159
111
 
160
- return {
161
- url: new URL(`ipfs://${cid}${url.pathname.replace(`/ipfs/${cid}`, '')}${url.search}${url.hash}`),
162
- protocol: 'ipfs',
163
- cidOrPeerIdOrDnsLink: cid,
164
- path: parts
165
- .filter(str => str !== '')
166
- .map(str => decodeURIComponent(str)),
167
- query: toQuery(url.searchParams),
168
- fragment: stripLeadingHash(url.hash)
169
- }
112
+ return new URL(`ipfs://${cid}${url.pathname.replace(`/ipfs/${cid}`, '')}${url.search}${url.hash}`)
170
113
  }
171
114
 
172
115
  // test for IPNS path gateway URL
@@ -178,17 +121,45 @@ export function parseURLString (urlString: string): ParsedURL {
178
121
  throw new InvalidParametersError(`Path gateway URL ${urlString} had no name`)
179
122
  }
180
123
 
181
- return {
182
- url: new URL(`ipns://${name}${url.pathname.replace(`/ipns/${name}`, '')}${url.search}${url.hash}`),
183
- protocol: 'ipns',
184
- cidOrPeerIdOrDnsLink: name,
185
- path: parts
186
- .filter(str => str !== '')
187
- .map(str => decodeURIComponent(str)),
188
- query: toQuery(url.searchParams),
189
- fragment: stripLeadingHash(url.hash)
190
- }
124
+ return new URL(`ipns://${name}${url.pathname.replace(`/ipns/${name}`, '')}${url.search}${url.hash}`)
191
125
  }
192
126
 
193
127
  throw new TypeError(`Invalid URL: ${urlString}, please use ipfs://, ipns://, or gateway URLs only`)
194
128
  }
129
+
130
+ /**
131
+ * Accepts the following url strings:
132
+ *
133
+ * - /ipfs/Qmfoo/path
134
+ * - /ipns/Qmfoo/path
135
+ * - ipfs://cid/path
136
+ * - ipns://name/path
137
+ * - http://cid.ipfs.example.com/path
138
+ * - http://name.ipns.example.com/path
139
+ * - http://example.com/ipfs/cid/path
140
+ * - http://example.com/ipns/name/path
141
+ */
142
+ export function parseURLString (urlString: string): URL {
143
+ // validate url
144
+ const url = toURL(urlString)
145
+
146
+ // treat IPNS keys that do not parse as PeerIds as DNSLink
147
+ if (url.protocol === 'ipns:') {
148
+ try {
149
+ peerIdFromString(url.hostname)
150
+ } catch {
151
+ url.protocol = 'dnslink:'
152
+ }
153
+ }
154
+
155
+ if (url.protocol === 'ipfs:') {
156
+ const cid = CID.parse(url.hostname)
157
+
158
+ // special case - peer id encoded as a CID
159
+ if (cid.code === CODEC_LIBP2P_KEY) {
160
+ return new URL(`ipns://${peerIdFromCID(cid)}${url.pathname}${url.search}${url.hash}`)
161
+ }
162
+ }
163
+
164
+ return url
165
+ }
@@ -8,9 +8,9 @@ import { parseURLString } from './parse-url-string.js'
8
8
  * E.g.
9
9
  *
10
10
  * - Qmfoo -> /ipfs/Qmfoo
11
- * - https://Qmfoo.ipfs.gateway.org -> /ipfs/Qmfoo
12
- * - https://gateway.org/ipfs/Qmfoo -> /ipfs/Qmfoo
13
- * - https://gateway.org/ipfs/Qmfoo/bar.txt -> /ipfs/Qmfoo
11
+ * - https://Qmfoo.ipfs.gateway.org -> ipfs://Qmfoo
12
+ * - https://gateway.org/ipfs/Qmfoo -> ipfs://Qmfoo
13
+ * - https://gateway.org/ipfs/Qmfoo/bar.txt -> ipfs://Qmfoo
14
14
  * - etc
15
15
  */
16
16
  export function resourceToSessionCacheKey (url: string | CID): string {
@@ -24,7 +24,7 @@ export function resourceToSessionCacheKey (url: string | CID): string {
24
24
  return `ipfs://${CID.parse(url.toString())}`
25
25
  } catch {}
26
26
 
27
- const { protocol, cidOrPeerIdOrDnsLink } = parseURLString(url.toString())
27
+ const { protocol, host } = parseURLString(url.toString())
28
28
 
29
- return `${protocol}://${cidOrPeerIdOrDnsLink}`
29
+ return `${protocol}//${host}`
30
30
  }
@@ -1,5 +1,4 @@
1
1
  import { InvalidRangeError } from '../errors.js'
2
- import type { CID } from 'multiformats/cid'
3
2
 
4
3
  interface CacheControlHeaderOptions {
5
4
  /**
@@ -24,8 +23,10 @@ export function setCacheControlHeader ({ ttl, protocol, response }: CacheControl
24
23
  // don't set the header if it's already set by a plugin
25
24
  return
26
25
  }
26
+
27
27
  let headerValue: string
28
- if (protocol === 'ipfs') {
28
+
29
+ if (protocol === 'ipfs:') {
29
30
  headerValue = 'public, max-age=29030400, immutable'
30
31
  } else if (ttl == null) {
31
32
  /**
@@ -42,59 +43,57 @@ export function setCacheControlHeader ({ ttl, protocol, response }: CacheControl
42
43
  }
43
44
 
44
45
  /**
45
- * This function returns the value of the `Content-Range` header for a given range.
46
+ * This function returns the value of the `Content-Range` header for a given
47
+ * range.
48
+ *
46
49
  * If you know the total size of the body, pass it as `byteSize`
47
50
  *
48
51
  * @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Range
49
52
  */
50
- export function getContentRangeHeader ({ byteStart, byteEnd, byteSize }: { byteStart: number | undefined, byteEnd: number | undefined, byteSize: number | undefined }): string {
51
- const total = byteSize ?? '*' // if we don't know the total size, we should use *
52
-
53
- if ((byteEnd ?? 0) >= (byteSize ?? Infinity)) {
54
- throw new InvalidRangeError('Invalid range: Range-end index is greater than or equal to the size of the file.')
55
- }
56
- if ((byteStart ?? 0) >= (byteSize ?? Infinity)) {
57
- throw new InvalidRangeError('Invalid range: Range-start index is greater than or equal to the size of the file.')
53
+ export function getContentRangeHeader (byteSize: number | bigint | string, byteStart?: number | bigint | string, byteEnd?: number | bigint | string): string {
54
+ if (byteStart != null) {
55
+ byteStart = BigInt(byteStart)
58
56
  }
59
57
 
60
- if (byteStart != null && byteEnd == null) {
61
- // only byteStart in range
62
- if (byteSize == null) {
63
- return `bytes */${total}`
64
- }
65
- return `bytes ${byteStart}-${byteSize - 1}/${byteSize}`
58
+ if (byteEnd != null) {
59
+ byteEnd = BigInt(byteEnd)
66
60
  }
67
61
 
68
- if (byteStart == null && byteEnd != null) {
69
- // only byteEnd in range
70
- if (byteSize == null) {
71
- return `bytes */${total}`
72
- }
73
- const end = byteSize - 1
74
- const start = end - byteEnd + 1
62
+ // if we don't know the total size, we should use *
63
+ const total = BigInt(byteSize)
75
64
 
76
- return `bytes ${start}-${end}/${byteSize}`
65
+ // validate start/end are not outside total size
66
+ if ((byteEnd ?? 0n) >= total) {
67
+ throw new InvalidRangeError('Invalid range: Range-end index is greater than or equal to the size of the file.')
77
68
  }
78
69
 
79
- if (byteStart == null && byteEnd == null) {
80
- // neither are provided, we can't return a valid range.
81
- return `bytes */${total}`
70
+ if ((byteStart ?? 0n) >= total) {
71
+ throw new InvalidRangeError('Invalid range: Range-start index is greater than or equal to the size of the file.')
82
72
  }
83
73
 
84
- return `bytes ${byteStart}-${byteEnd}/${total}`
85
- }
74
+ let range = '*'
86
75
 
87
- /**
88
- * Sets the `X-Ipfs-Roots` header on the response if it exists.
89
- *
90
- * @see https://specs.ipfs.tech/http-gateways/path-gateway/#x-ipfs-roots-response-header
91
- */
92
- export function setIpfsRoots (response: Response, ipfsRoots?: CID[]): void {
93
- if (ipfsRoots != null) {
94
- response.headers.set('X-Ipfs-Roots', getIpfsRoots(ipfsRoots))
76
+ if (byteStart == null) {
77
+ if (byteEnd != null) {
78
+ if (byteEnd < 0n) {
79
+ range = `${total + byteEnd}-${total - 1n}`
80
+ } else {
81
+ range = `0-${byteEnd}`
82
+ }
83
+ }
84
+ } else {
85
+ if (byteEnd == null) {
86
+ let end = '*'
87
+
88
+ if (byteSize != null) {
89
+ end = `${total - 1n}`
90
+ }
91
+
92
+ range = `${byteStart}-${end}`
93
+ } else {
94
+ range = `${byteStart}-${byteEnd}`
95
+ }
95
96
  }
96
- }
97
97
 
98
- export function getIpfsRoots (ipfsRoots: CID[]): string {
99
- return ipfsRoots.map(cid => cid.toV1().toString()).join(',')
98
+ return `bytes ${range}/${total}`
100
99
  }