@helia/verified-fetch 0.0.0-8db7792 → 0.0.0-a04e041
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 +33 -0
- package/dist/index.min.js +4 -4
- package/dist/src/index.d.ts +36 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +33 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/utils/get-content-disposition-filename.d.ts +6 -0
- package/dist/src/utils/get-content-disposition-filename.d.ts.map +1 -0
- package/dist/src/utils/get-content-disposition-filename.js +16 -0
- package/dist/src/utils/get-content-disposition-filename.js.map +1 -0
- package/dist/src/utils/parse-url-string.d.ts +2 -0
- package/dist/src/utils/parse-url-string.d.ts.map +1 -1
- package/dist/src/utils/parse-url-string.js +6 -0
- package/dist/src/utils/parse-url-string.js.map +1 -1
- package/dist/src/utils/responses.d.ts +4 -0
- package/dist/src/utils/responses.d.ts.map +1 -0
- package/dist/src/utils/responses.js +21 -0
- package/dist/src/utils/responses.js.map +1 -0
- package/dist/src/utils/select-output-type.d.ts +12 -0
- package/dist/src/utils/select-output-type.d.ts.map +1 -0
- package/dist/src/utils/select-output-type.js +147 -0
- package/dist/src/utils/select-output-type.js.map +1 -0
- package/dist/src/verified-fetch.d.ts +17 -15
- package/dist/src/verified-fetch.d.ts.map +1 -1
- package/dist/src/verified-fetch.js +211 -129
- package/dist/src/verified-fetch.js.map +1 -1
- package/package.json +18 -12
- package/src/index.ts +37 -0
- package/src/utils/get-content-disposition-filename.ts +18 -0
- package/src/utils/parse-url-string.ts +11 -1
- package/src/utils/responses.ts +22 -0
- package/src/utils/select-output-type.ts +166 -0
- package/src/verified-fetch.ts +237 -134
|
@@ -19,6 +19,8 @@ export interface ParseUrlStringOptions extends ProgressOptions<ResolveProgressEv
|
|
|
19
19
|
|
|
20
20
|
export interface ParsedUrlQuery extends Record<string, string | unknown> {
|
|
21
21
|
format?: RequestFormatShorthand
|
|
22
|
+
download?: boolean
|
|
23
|
+
filename?: string
|
|
22
24
|
}
|
|
23
25
|
|
|
24
26
|
export interface ParsedUrlStringResults {
|
|
@@ -109,7 +111,7 @@ export async function parseUrlString ({ urlString, ipns, logger }: ParseUrlStrin
|
|
|
109
111
|
}
|
|
110
112
|
|
|
111
113
|
// parse query string
|
|
112
|
-
const query: Record<string,
|
|
114
|
+
const query: Record<string, any> = {}
|
|
113
115
|
|
|
114
116
|
if (queryString != null && queryString.length > 0) {
|
|
115
117
|
const queryParts = queryString.split('&')
|
|
@@ -117,6 +119,14 @@ export async function parseUrlString ({ urlString, ipns, logger }: ParseUrlStrin
|
|
|
117
119
|
const [key, value] = part.split('=')
|
|
118
120
|
query[key] = decodeURIComponent(value)
|
|
119
121
|
}
|
|
122
|
+
|
|
123
|
+
if (query.download != null) {
|
|
124
|
+
query.download = query.download === 'true'
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (query.filename != null) {
|
|
128
|
+
query.filename = query.filename.toString()
|
|
129
|
+
}
|
|
120
130
|
}
|
|
121
131
|
|
|
122
132
|
/**
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export function okResponse (body?: BodyInit | null): Response {
|
|
2
|
+
return new Response(body, {
|
|
3
|
+
status: 200,
|
|
4
|
+
statusText: 'OK'
|
|
5
|
+
})
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function notSupportedResponse (body?: BodyInit | null): Response {
|
|
9
|
+
const response = new Response(body, {
|
|
10
|
+
status: 501,
|
|
11
|
+
statusText: 'Not Implemented'
|
|
12
|
+
})
|
|
13
|
+
response.headers.set('X-Content-Type-Options', 'nosniff') // see https://specs.ipfs.tech/http-gateways/path-gateway/#x-content-type-options-response-header
|
|
14
|
+
return response
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function notAcceptableResponse (body?: BodyInit | null): Response {
|
|
18
|
+
return new Response(body, {
|
|
19
|
+
status: 406,
|
|
20
|
+
statusText: 'Not Acceptable'
|
|
21
|
+
})
|
|
22
|
+
}
|
|
@@ -0,0 +1,166 @@
|
|
|
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 type { RequestFormatShorthand } from '../types.js'
|
|
7
|
+
import type { CID } from 'multiformats/cid'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* This maps supported response types for each codec supported by verified-fetch
|
|
11
|
+
*/
|
|
12
|
+
const CID_TYPE_MAP: Record<number, string[]> = {
|
|
13
|
+
[dagCborCode]: [
|
|
14
|
+
'application/json',
|
|
15
|
+
'application/vnd.ipld.dag-cbor',
|
|
16
|
+
'application/cbor',
|
|
17
|
+
'application/vnd.ipld.dag-json',
|
|
18
|
+
'application/octet-stream',
|
|
19
|
+
'application/vnd.ipld.raw',
|
|
20
|
+
'application/vnd.ipfs.ipns-record',
|
|
21
|
+
'application/vnd.ipld.car'
|
|
22
|
+
],
|
|
23
|
+
[dagJsonCode]: [
|
|
24
|
+
'application/json',
|
|
25
|
+
'application/vnd.ipld.dag-cbor',
|
|
26
|
+
'application/cbor',
|
|
27
|
+
'application/vnd.ipld.dag-json',
|
|
28
|
+
'application/octet-stream',
|
|
29
|
+
'application/vnd.ipld.raw',
|
|
30
|
+
'application/vnd.ipfs.ipns-record',
|
|
31
|
+
'application/vnd.ipld.car'
|
|
32
|
+
],
|
|
33
|
+
[jsonCode]: [
|
|
34
|
+
'application/json',
|
|
35
|
+
'application/vnd.ipld.dag-cbor',
|
|
36
|
+
'application/cbor',
|
|
37
|
+
'application/vnd.ipld.dag-json',
|
|
38
|
+
'application/octet-stream',
|
|
39
|
+
'application/vnd.ipld.raw',
|
|
40
|
+
'application/vnd.ipfs.ipns-record',
|
|
41
|
+
'application/vnd.ipld.car'
|
|
42
|
+
],
|
|
43
|
+
[dagPbCode]: [
|
|
44
|
+
'application/octet-stream',
|
|
45
|
+
'application/json',
|
|
46
|
+
'application/vnd.ipld.dag-cbor',
|
|
47
|
+
'application/cbor',
|
|
48
|
+
'application/vnd.ipld.dag-json',
|
|
49
|
+
'application/vnd.ipld.raw',
|
|
50
|
+
'application/vnd.ipfs.ipns-record',
|
|
51
|
+
'application/vnd.ipld.car',
|
|
52
|
+
'application/x-tar'
|
|
53
|
+
],
|
|
54
|
+
[rawCode]: [
|
|
55
|
+
'application/octet-stream',
|
|
56
|
+
'application/vnd.ipld.raw',
|
|
57
|
+
'application/vnd.ipfs.ipns-record',
|
|
58
|
+
'application/vnd.ipld.car'
|
|
59
|
+
]
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Selects an output mime-type based on the CID and a passed `Accept` header
|
|
64
|
+
*/
|
|
65
|
+
export function selectOutputType (cid: CID, accept?: string): string | undefined {
|
|
66
|
+
const cidMimeTypes = CID_TYPE_MAP[cid.code]
|
|
67
|
+
|
|
68
|
+
if (accept != null) {
|
|
69
|
+
return chooseMimeType(accept, cidMimeTypes)
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function chooseMimeType (accept: string, validMimeTypes: string[]): string | undefined {
|
|
74
|
+
const requestedMimeTypes = accept
|
|
75
|
+
.split(',')
|
|
76
|
+
.map(s => {
|
|
77
|
+
const parts = s.trim().split(';')
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
mimeType: `${parts[0]}`.trim(),
|
|
81
|
+
weight: parseQFactor(parts[1])
|
|
82
|
+
}
|
|
83
|
+
})
|
|
84
|
+
.sort((a, b) => {
|
|
85
|
+
if (a.weight === b.weight) {
|
|
86
|
+
return 0
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (a.weight > b.weight) {
|
|
90
|
+
return -1
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return 1
|
|
94
|
+
})
|
|
95
|
+
.map(s => s.mimeType)
|
|
96
|
+
|
|
97
|
+
for (const headerFormat of requestedMimeTypes) {
|
|
98
|
+
for (const mimeType of validMimeTypes) {
|
|
99
|
+
if (headerFormat.includes(mimeType)) {
|
|
100
|
+
return mimeType
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
if (headerFormat === '*/*') {
|
|
104
|
+
return mimeType
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (headerFormat.startsWith('*/') && mimeType.split('/')[1] === headerFormat.split('/')[1]) {
|
|
108
|
+
return mimeType
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (headerFormat.endsWith('/*') && mimeType.split('/')[0] === headerFormat.split('/')[0]) {
|
|
112
|
+
return mimeType
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Parses q-factor weighting from the accept header to allow letting some mime
|
|
120
|
+
* types take precedence over others.
|
|
121
|
+
*
|
|
122
|
+
* If the q-factor for an acceptable mime representation is omitted it defaults
|
|
123
|
+
* to `1`.
|
|
124
|
+
*
|
|
125
|
+
* All specified values should be in the range 0-1.
|
|
126
|
+
*
|
|
127
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept#q
|
|
128
|
+
*/
|
|
129
|
+
function parseQFactor (str?: string): number {
|
|
130
|
+
if (str != null) {
|
|
131
|
+
str = str.trim()
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (str == null || !str.startsWith('q=')) {
|
|
135
|
+
return 1
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
const factor = parseFloat(str.replace('q=', ''))
|
|
139
|
+
|
|
140
|
+
if (isNaN(factor)) {
|
|
141
|
+
return 0
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return factor
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const FORMAT_TO_MIME_TYPE: Record<RequestFormatShorthand, string> = {
|
|
148
|
+
raw: 'application/vnd.ipld.raw',
|
|
149
|
+
car: 'application/vnd.ipld.car',
|
|
150
|
+
'dag-json': 'application/vnd.ipld.dag-json',
|
|
151
|
+
'dag-cbor': 'application/vnd.ipld.dag-cbor',
|
|
152
|
+
json: 'application/json',
|
|
153
|
+
cbor: 'application/cbor',
|
|
154
|
+
'ipns-record': 'application/vnd.ipfs.ipns-record',
|
|
155
|
+
tar: 'application/x-tar'
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Converts a `format=...` query param to a mime type as would be found in the
|
|
160
|
+
* `Accept` header, if a valid mapping is available
|
|
161
|
+
*/
|
|
162
|
+
export function queryFormatToAcceptHeader (format?: RequestFormatShorthand): string | undefined {
|
|
163
|
+
if (format != null) {
|
|
164
|
+
return FORMAT_TO_MIME_TYPE[format]
|
|
165
|
+
}
|
|
166
|
+
}
|