@helia/verified-fetch 4.1.0 → 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.
- package/README.md +6 -40
- package/dist/index.min.js +73 -534
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +2 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/index.d.ts +162 -68
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -43
- package/dist/src/index.js.map +1 -1
- package/dist/src/plugins/index.d.ts +0 -5
- package/dist/src/plugins/index.d.ts.map +1 -1
- package/dist/src/plugins/index.js +0 -4
- package/dist/src/plugins/index.js.map +1 -1
- package/dist/src/plugins/plugin-base.d.ts +8 -9
- package/dist/src/plugins/plugin-base.d.ts.map +1 -1
- package/dist/src/plugins/plugin-base.js +5 -6
- package/dist/src/plugins/plugin-base.js.map +1 -1
- package/dist/src/plugins/plugin-handle-car.d.ts +3 -3
- package/dist/src/plugins/plugin-handle-car.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-car.js +38 -39
- package/dist/src/plugins/plugin-handle-car.js.map +1 -1
- package/dist/src/plugins/plugin-handle-ipld.d.ts +12 -0
- package/dist/src/plugins/plugin-handle-ipld.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-ipld.js +83 -0
- package/dist/src/plugins/plugin-handle-ipld.js.map +1 -0
- package/dist/src/plugins/plugin-handle-ipns-record.d.ts +3 -3
- package/dist/src/plugins/plugin-handle-ipns-record.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-ipns-record.js +25 -34
- package/dist/src/plugins/plugin-handle-ipns-record.js.map +1 -1
- package/dist/src/plugins/plugin-handle-tar.d.ts +3 -3
- package/dist/src/plugins/plugin-handle-tar.d.ts.map +1 -1
- package/dist/src/plugins/plugin-handle-tar.js +20 -22
- package/dist/src/plugins/plugin-handle-tar.js.map +1 -1
- package/dist/src/plugins/plugin-handle-unixfs.d.ts +14 -0
- package/dist/src/plugins/plugin-handle-unixfs.d.ts.map +1 -0
- package/dist/src/plugins/plugin-handle-unixfs.js +180 -0
- package/dist/src/plugins/plugin-handle-unixfs.js.map +1 -0
- package/dist/src/plugins/types.d.ts +1 -77
- package/dist/src/plugins/types.d.ts.map +1 -1
- package/dist/src/url-resolver.d.ts +29 -11
- package/dist/src/url-resolver.d.ts.map +1 -1
- package/dist/src/url-resolver.js +152 -74
- package/dist/src/url-resolver.js.map +1 -1
- package/dist/src/utils/content-type-parser.d.ts.map +1 -1
- package/dist/src/utils/content-type-parser.js +4 -3
- package/dist/src/utils/content-type-parser.js.map +1 -1
- package/dist/src/utils/content-types.d.ts +26 -0
- package/dist/src/utils/content-types.d.ts.map +1 -0
- package/dist/src/utils/content-types.js +137 -0
- package/dist/src/utils/content-types.js.map +1 -0
- package/dist/src/utils/convert-output.d.ts +17 -0
- package/dist/src/utils/convert-output.d.ts.map +1 -0
- package/dist/src/utils/convert-output.js +176 -0
- package/dist/src/utils/convert-output.js.map +1 -0
- package/dist/src/utils/error-to-response.d.ts +3 -0
- package/dist/src/utils/error-to-response.d.ts.map +1 -0
- package/dist/src/utils/error-to-response.js +40 -0
- package/dist/src/utils/error-to-response.js.map +1 -0
- package/dist/src/utils/get-content-disposition-filename.d.ts +1 -1
- package/dist/src/utils/get-content-disposition-filename.d.ts.map +1 -1
- package/dist/src/utils/get-content-disposition-filename.js +4 -0
- package/dist/src/utils/get-content-disposition-filename.js.map +1 -1
- package/dist/src/utils/get-e-tag.d.ts +20 -15
- package/dist/src/utils/get-e-tag.d.ts.map +1 -1
- package/dist/src/utils/get-e-tag.js +8 -22
- package/dist/src/utils/get-e-tag.js.map +1 -1
- package/dist/src/utils/get-offset-and-length.d.ts +12 -2
- package/dist/src/utils/get-offset-and-length.d.ts.map +1 -1
- package/dist/src/utils/get-offset-and-length.js +63 -21
- package/dist/src/utils/get-offset-and-length.js.map +1 -1
- package/dist/src/utils/get-range-header.d.ts +22 -0
- package/dist/src/utils/get-range-header.d.ts.map +1 -0
- package/dist/src/utils/get-range-header.js +69 -0
- package/dist/src/utils/get-range-header.js.map +1 -0
- package/dist/src/utils/parse-url-string.d.ts +2 -1
- package/dist/src/utils/parse-url-string.d.ts.map +1 -1
- package/dist/src/utils/parse-url-string.js +46 -71
- package/dist/src/utils/parse-url-string.js.map +1 -1
- package/dist/src/utils/resource-to-cache-key.d.ts +3 -3
- package/dist/src/utils/resource-to-cache-key.js +5 -5
- package/dist/src/utils/resource-to-cache-key.js.map +1 -1
- package/dist/src/utils/response-headers.d.ts +4 -14
- package/dist/src/utils/response-headers.d.ts.map +1 -1
- package/dist/src/utils/response-headers.js +36 -36
- package/dist/src/utils/response-headers.js.map +1 -1
- package/dist/src/utils/responses.d.ts +30 -11
- package/dist/src/utils/responses.d.ts.map +1 -1
- package/dist/src/utils/responses.js +146 -39
- package/dist/src/utils/responses.js.map +1 -1
- package/dist/src/verified-fetch.d.ts +16 -15
- package/dist/src/verified-fetch.d.ts.map +1 -1
- package/dist/src/verified-fetch.js +307 -236
- package/dist/src/verified-fetch.js.map +1 -1
- package/dist/typedoc-urls.json +64 -45
- package/package.json +4 -3
- package/src/constants.ts +3 -0
- package/src/index.ts +203 -71
- package/src/plugins/index.ts +0 -6
- package/src/plugins/plugin-base.ts +8 -10
- package/src/plugins/plugin-handle-car.ts +48 -46
- package/src/plugins/plugin-handle-ipld.ts +93 -0
- package/src/plugins/plugin-handle-ipns-record.ts +31 -41
- package/src/plugins/plugin-handle-tar.ts +25 -29
- package/src/plugins/plugin-handle-unixfs.ts +217 -0
- package/src/plugins/types.ts +0 -86
- package/src/url-resolver.ts +197 -83
- package/src/utils/content-type-parser.ts +4 -3
- package/src/utils/content-types.ts +159 -0
- package/src/utils/convert-output.ts +187 -0
- package/src/utils/error-to-response.ts +49 -0
- package/src/utils/get-content-disposition-filename.ts +7 -1
- package/src/utils/get-e-tag.ts +26 -35
- package/src/utils/get-offset-and-length.ts +75 -21
- package/src/utils/get-range-header.ts +107 -0
- package/src/utils/parse-url-string.ts +51 -80
- package/src/utils/resource-to-cache-key.ts +5 -5
- package/src/utils/response-headers.ts +40 -41
- package/src/utils/responses.ts +186 -45
- package/src/verified-fetch.ts +359 -267
- package/dist/src/plugins/plugin-handle-byte-range-context.d.ts +0 -14
- package/dist/src/plugins/plugin-handle-byte-range-context.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-byte-range-context.js +0 -25
- package/dist/src/plugins/plugin-handle-byte-range-context.js.map +0 -1
- package/dist/src/plugins/plugin-handle-cbor.d.ts +0 -17
- package/dist/src/plugins/plugin-handle-cbor.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-cbor.js +0 -94
- package/dist/src/plugins/plugin-handle-cbor.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.d.ts +0 -27
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.js +0 -279
- package/dist/src/plugins/plugin-handle-dag-cbor-html-preview.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor.d.ts +0 -17
- package/dist/src/plugins/plugin-handle-dag-cbor.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-cbor.js +0 -66
- package/dist/src/plugins/plugin-handle-dag-cbor.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-pb.d.ts +0 -17
- package/dist/src/plugins/plugin-handle-dag-pb.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-pb.js +0 -209
- package/dist/src/plugins/plugin-handle-dag-pb.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-walk.d.ts +0 -21
- package/dist/src/plugins/plugin-handle-dag-walk.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dag-walk.js +0 -95
- package/dist/src/plugins/plugin-handle-dag-walk.js.map +0 -1
- package/dist/src/plugins/plugin-handle-dir-index-html.d.ts +0 -10
- package/dist/src/plugins/plugin-handle-dir-index-html.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-dir-index-html.js +0 -59
- package/dist/src/plugins/plugin-handle-dir-index-html.js.map +0 -1
- package/dist/src/plugins/plugin-handle-json.d.ts +0 -12
- package/dist/src/plugins/plugin-handle-json.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-json.js +0 -73
- package/dist/src/plugins/plugin-handle-json.js.map +0 -1
- package/dist/src/plugins/plugin-handle-raw.d.ts +0 -9
- package/dist/src/plugins/plugin-handle-raw.d.ts.map +0 -1
- package/dist/src/plugins/plugin-handle-raw.js +0 -92
- package/dist/src/plugins/plugin-handle-raw.js.map +0 -1
- package/dist/src/plugins/plugins.d.ts +0 -6
- package/dist/src/plugins/plugins.d.ts.map +0 -1
- package/dist/src/plugins/plugins.js +0 -6
- package/dist/src/plugins/plugins.js.map +0 -1
- package/dist/src/utils/byte-range-context.d.ts +0 -103
- package/dist/src/utils/byte-range-context.d.ts.map +0 -1
- package/dist/src/utils/byte-range-context.js +0 -504
- package/dist/src/utils/byte-range-context.js.map +0 -1
- package/dist/src/utils/dag-cbor-to-safe-json.d.ts +0 -15
- package/dist/src/utils/dag-cbor-to-safe-json.d.ts.map +0 -1
- package/dist/src/utils/dag-cbor-to-safe-json.js +0 -54
- package/dist/src/utils/dag-cbor-to-safe-json.js.map +0 -1
- package/dist/src/utils/dir-index-html.d.ts +0 -19
- package/dist/src/utils/dir-index-html.d.ts.map +0 -1
- package/dist/src/utils/dir-index-html.js +0 -438
- package/dist/src/utils/dir-index-html.js.map +0 -1
- package/dist/src/utils/get-peer-id-from-string.d.ts +0 -3
- package/dist/src/utils/get-peer-id-from-string.d.ts.map +0 -1
- package/dist/src/utils/get-peer-id-from-string.js +0 -10
- package/dist/src/utils/get-peer-id-from-string.js.map +0 -1
- package/dist/src/utils/get-resolved-accept-header.d.ts +0 -9
- package/dist/src/utils/get-resolved-accept-header.d.ts.map +0 -1
- package/dist/src/utils/get-resolved-accept-header.js +0 -27
- package/dist/src/utils/get-resolved-accept-header.js.map +0 -1
- package/dist/src/utils/get-stream-from-async-iterable.d.ts +0 -9
- package/dist/src/utils/get-stream-from-async-iterable.d.ts.map +0 -1
- package/dist/src/utils/get-stream-from-async-iterable.js +0 -43
- package/dist/src/utils/get-stream-from-async-iterable.js.map +0 -1
- package/dist/src/utils/handle-redirects.d.ts +0 -16
- package/dist/src/utils/handle-redirects.d.ts.map +0 -1
- package/dist/src/utils/handle-redirects.js +0 -84
- package/dist/src/utils/handle-redirects.js.map +0 -1
- package/dist/src/utils/is-accept-explicit.d.ts +0 -15
- package/dist/src/utils/is-accept-explicit.d.ts.map +0 -1
- package/dist/src/utils/is-accept-explicit.js +0 -26
- package/dist/src/utils/is-accept-explicit.js.map +0 -1
- package/dist/src/utils/request-headers.d.ts +0 -13
- package/dist/src/utils/request-headers.d.ts.map +0 -1
- package/dist/src/utils/request-headers.js +0 -63
- package/dist/src/utils/request-headers.js.map +0 -1
- package/dist/src/utils/select-output-type.d.ts +0 -17
- package/dist/src/utils/select-output-type.d.ts.map +0 -1
- package/dist/src/utils/select-output-type.js +0 -153
- package/dist/src/utils/select-output-type.js.map +0 -1
- package/dist/src/utils/tlru.d.ts +0 -15
- package/dist/src/utils/tlru.d.ts.map +0 -1
- package/dist/src/utils/tlru.js +0 -34
- package/dist/src/utils/tlru.js.map +0 -1
- package/dist/src/utils/walk-path.d.ts +0 -27
- package/dist/src/utils/walk-path.d.ts.map +0 -1
- package/dist/src/utils/walk-path.js +0 -45
- package/dist/src/utils/walk-path.js.map +0 -1
- package/src/plugins/plugin-handle-byte-range-context.ts +0 -30
- package/src/plugins/plugin-handle-cbor.ts +0 -107
- package/src/plugins/plugin-handle-dag-cbor-html-preview.ts +0 -295
- package/src/plugins/plugin-handle-dag-cbor.ts +0 -83
- package/src/plugins/plugin-handle-dag-pb.ts +0 -248
- package/src/plugins/plugin-handle-dag-walk.ts +0 -110
- package/src/plugins/plugin-handle-dir-index-html.ts +0 -72
- package/src/plugins/plugin-handle-json.ts +0 -80
- package/src/plugins/plugin-handle-raw.ts +0 -110
- package/src/plugins/plugins.ts +0 -5
- package/src/utils/byte-range-context.ts +0 -597
- package/src/utils/dag-cbor-to-safe-json.ts +0 -63
- package/src/utils/dir-index-html.ts +0 -505
- package/src/utils/get-peer-id-from-string.ts +0 -12
- package/src/utils/get-resolved-accept-header.ts +0 -42
- package/src/utils/get-stream-from-async-iterable.ts +0 -49
- package/src/utils/handle-redirects.ts +0 -109
- package/src/utils/is-accept-explicit.ts +0 -38
- package/src/utils/request-headers.ts +0 -65
- package/src/utils/select-output-type.ts +0 -175
- package/src/utils/tlru.ts +0 -42
- package/src/utils/walk-path.ts +0 -68
|
@@ -0,0 +1,159 @@
|
|
|
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 { ContentType } from '../index.ts'
|
|
8
|
+
import type { CID } from 'multiformats/cid'
|
|
9
|
+
|
|
10
|
+
export const MEDIA_TYPE_DAG_CBOR = 'application/vnd.ipld.dag-cbor'
|
|
11
|
+
export const MEDIA_TYPE_CBOR = 'application/cbor'
|
|
12
|
+
export const MEDIA_TYPE_DAG_JSON = 'application/vnd.ipld.dag-json'
|
|
13
|
+
export const MEDIA_TYPE_JSON = 'application/json'
|
|
14
|
+
export const MEDIA_TYPE_RAW = 'application/vnd.ipld.raw'
|
|
15
|
+
export const MEDIA_TYPE_OCTET_STREAM = 'application/octet-stream'
|
|
16
|
+
export const MEDIA_TYPE_IPNS_RECORD = 'application/vnd.ipfs.ipns-record'
|
|
17
|
+
export const MEDIA_TYPE_CAR = 'application/vnd.ipld.car'
|
|
18
|
+
export const MEDIA_TYPE_TAR = 'application/x-tar'
|
|
19
|
+
export const MEDIA_TYPE_DAG_PB = 'application/vnd.ipld.dag-pb'
|
|
20
|
+
|
|
21
|
+
export const CONTENT_TYPE_OCTET_STREAM: ContentType = {
|
|
22
|
+
mediaType: MEDIA_TYPE_OCTET_STREAM,
|
|
23
|
+
codecs: [rawCode, jsonCode, dagJsonCode, CODEC_CBOR, dagCborCode, dagPbCode],
|
|
24
|
+
immutable: true,
|
|
25
|
+
extension: '.bin',
|
|
26
|
+
etag: '',
|
|
27
|
+
disposition: 'attachment'
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export const CONTENT_TYPE_DAG_CBOR: ContentType = {
|
|
31
|
+
mediaType: MEDIA_TYPE_DAG_CBOR,
|
|
32
|
+
codecs: [dagCborCode, CODEC_CBOR, dagJsonCode, jsonCode, dagPbCode, rawCode],
|
|
33
|
+
immutable: true,
|
|
34
|
+
extension: '.cbor',
|
|
35
|
+
etag: '.dag-cbor',
|
|
36
|
+
disposition: 'attachment'
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export const CONTENT_TYPE_CBOR: ContentType = {
|
|
40
|
+
mediaType: MEDIA_TYPE_CBOR,
|
|
41
|
+
codecs: [CODEC_CBOR, dagCborCode, dagJsonCode, jsonCode, dagPbCode, rawCode],
|
|
42
|
+
immutable: true,
|
|
43
|
+
extension: '.cbor',
|
|
44
|
+
etag: '.cbor',
|
|
45
|
+
disposition: 'attachment'
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export const CONTENT_TYPE_DAG_JSON: ContentType = {
|
|
49
|
+
mediaType: MEDIA_TYPE_DAG_JSON,
|
|
50
|
+
codecs: [dagJsonCode, jsonCode, dagCborCode, CODEC_CBOR, dagPbCode, rawCode],
|
|
51
|
+
immutable: true,
|
|
52
|
+
extension: '.json',
|
|
53
|
+
etag: '.dag-json',
|
|
54
|
+
disposition: 'inline'
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export const CONTENT_TYPE_JSON: ContentType = {
|
|
58
|
+
mediaType: MEDIA_TYPE_JSON,
|
|
59
|
+
codecs: [jsonCode, dagJsonCode, dagCborCode, CODEC_CBOR, dagPbCode, rawCode],
|
|
60
|
+
immutable: true,
|
|
61
|
+
extension: '.json',
|
|
62
|
+
etag: '.json',
|
|
63
|
+
disposition: 'inline'
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const CONTENT_TYPE_RAW: ContentType = {
|
|
67
|
+
mediaType: MEDIA_TYPE_RAW,
|
|
68
|
+
codecs: [rawCode, jsonCode, dagJsonCode, CODEC_CBOR, dagCborCode, dagPbCode],
|
|
69
|
+
immutable: true,
|
|
70
|
+
extension: '.raw',
|
|
71
|
+
etag: '.raw',
|
|
72
|
+
disposition: 'attachment'
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const CONTENT_TYPE_IPNS: ContentType = {
|
|
76
|
+
mediaType: MEDIA_TYPE_IPNS_RECORD,
|
|
77
|
+
codecs: [],
|
|
78
|
+
immutable: false,
|
|
79
|
+
extension: '.bin',
|
|
80
|
+
etag: '.bin',
|
|
81
|
+
disposition: 'attachment'
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export const CONTENT_TYPE_CAR: ContentType = {
|
|
85
|
+
mediaType: MEDIA_TYPE_CAR,
|
|
86
|
+
codecs: [rawCode, jsonCode, dagJsonCode, CODEC_CBOR, dagCborCode, dagPbCode],
|
|
87
|
+
immutable: false,
|
|
88
|
+
extension: '.car',
|
|
89
|
+
etag: '.car',
|
|
90
|
+
disposition: 'attachment'
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const CONTENT_TYPE_TAR: ContentType = {
|
|
94
|
+
mediaType: MEDIA_TYPE_TAR,
|
|
95
|
+
codecs: [rawCode, dagPbCode],
|
|
96
|
+
immutable: false,
|
|
97
|
+
extension: '.x-tar',
|
|
98
|
+
etag: '.x-tar',
|
|
99
|
+
disposition: 'attachment'
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export const CONTENT_TYPES: ContentType[] = [
|
|
103
|
+
CONTENT_TYPE_DAG_CBOR,
|
|
104
|
+
CONTENT_TYPE_CBOR,
|
|
105
|
+
CONTENT_TYPE_DAG_JSON,
|
|
106
|
+
CONTENT_TYPE_JSON,
|
|
107
|
+
CONTENT_TYPE_RAW,
|
|
108
|
+
CONTENT_TYPE_IPNS,
|
|
109
|
+
CONTENT_TYPE_CAR,
|
|
110
|
+
CONTENT_TYPE_TAR,
|
|
111
|
+
CONTENT_TYPE_OCTET_STREAM
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
export function getContentType (mediaType?: string | null): ContentType | undefined {
|
|
115
|
+
return CONTENT_TYPES
|
|
116
|
+
.find(m => m.mediaType === mediaType)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function getContentTypesForCid (cid?: CID): ContentType[] {
|
|
120
|
+
if (cid == null) {
|
|
121
|
+
return []
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return CONTENT_TYPES
|
|
125
|
+
.filter(m => m.codecs.includes(cid.code))
|
|
126
|
+
.sort((a, b) => {
|
|
127
|
+
// prefer content types where the CID code is earlier in the list of
|
|
128
|
+
// supported codecs
|
|
129
|
+
const posA = a.codecs.indexOf(cid.code)
|
|
130
|
+
const posB = b.codecs.indexOf(cid.code)
|
|
131
|
+
|
|
132
|
+
if (posA < posB) {
|
|
133
|
+
return -1
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (posB < posA) {
|
|
137
|
+
return 1
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
return 0
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function getSupportedContentTypes (protocol: string = 'ipfs:', cid?: CID): ContentType[] {
|
|
145
|
+
let contentTypes = getContentTypesForCid(cid)
|
|
146
|
+
|
|
147
|
+
if (protocol === 'ipfs:' && contentTypes.length === 0) {
|
|
148
|
+
contentTypes = [
|
|
149
|
+
CONTENT_TYPE_RAW,
|
|
150
|
+
CONTENT_TYPE_OCTET_STREAM
|
|
151
|
+
]
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (protocol === 'ipns:') {
|
|
155
|
+
contentTypes.push(CONTENT_TYPE_IPNS)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return contentTypes
|
|
159
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import * as dagCbor from '@ipld/dag-cbor'
|
|
2
|
+
import * as dagJson from '@ipld/dag-json'
|
|
3
|
+
import * as dagPb from '@ipld/dag-pb'
|
|
4
|
+
import * as json from 'multiformats/codecs/json'
|
|
5
|
+
import * as raw from 'multiformats/codecs/raw'
|
|
6
|
+
import { identity } from 'multiformats/hashes/identity'
|
|
7
|
+
import { CODEC_CBOR } from '../constants.ts'
|
|
8
|
+
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
|
+
import type { AcceptHeader, ContentType } from '../index.ts'
|
|
10
|
+
import type { CID } from 'multiformats/cid'
|
|
11
|
+
|
|
12
|
+
const CONVERSIONS: Record<number, Record<string, (buf: Uint8Array) => Uint8Array>> = {
|
|
13
|
+
[dagCbor.code]: {
|
|
14
|
+
[MEDIA_TYPE_JSON]: (buf) => {
|
|
15
|
+
return dagJson.encode(dagCbor.decode(buf))
|
|
16
|
+
},
|
|
17
|
+
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
18
|
+
return dagJson.encode(dagCbor.decode(buf))
|
|
19
|
+
},
|
|
20
|
+
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
21
|
+
return buf
|
|
22
|
+
},
|
|
23
|
+
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
24
|
+
return buf
|
|
25
|
+
},
|
|
26
|
+
[MEDIA_TYPE_RAW]: (buf) => {
|
|
27
|
+
return buf
|
|
28
|
+
},
|
|
29
|
+
[MEDIA_TYPE_OCTET_STREAM]: (buf) => {
|
|
30
|
+
return buf
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
[CODEC_CBOR]: {
|
|
34
|
+
[MEDIA_TYPE_JSON]: (buf) => {
|
|
35
|
+
return dagJson.encode(dagCbor.decode(buf))
|
|
36
|
+
},
|
|
37
|
+
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
38
|
+
return dagJson.encode(dagCbor.decode(buf))
|
|
39
|
+
},
|
|
40
|
+
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
41
|
+
return buf
|
|
42
|
+
},
|
|
43
|
+
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
44
|
+
return buf
|
|
45
|
+
},
|
|
46
|
+
[MEDIA_TYPE_RAW]: (buf) => {
|
|
47
|
+
return buf
|
|
48
|
+
},
|
|
49
|
+
[MEDIA_TYPE_OCTET_STREAM]: (buf) => {
|
|
50
|
+
return buf
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
[dagJson.code]: {
|
|
54
|
+
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
55
|
+
return dagCbor.encode(dagJson.decode(buf))
|
|
56
|
+
},
|
|
57
|
+
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
58
|
+
return dagCbor.encode(dagJson.decode(buf))
|
|
59
|
+
},
|
|
60
|
+
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
61
|
+
return buf
|
|
62
|
+
},
|
|
63
|
+
[MEDIA_TYPE_JSON]: (buf) => {
|
|
64
|
+
return buf
|
|
65
|
+
},
|
|
66
|
+
[MEDIA_TYPE_RAW]: (buf) => {
|
|
67
|
+
return buf
|
|
68
|
+
},
|
|
69
|
+
[MEDIA_TYPE_OCTET_STREAM]: (buf) => {
|
|
70
|
+
return buf
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
[json.code]: {
|
|
74
|
+
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
75
|
+
return dagCbor.encode(json.decode(buf))
|
|
76
|
+
},
|
|
77
|
+
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
78
|
+
return dagCbor.encode(json.decode(buf))
|
|
79
|
+
},
|
|
80
|
+
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
81
|
+
return buf
|
|
82
|
+
},
|
|
83
|
+
[MEDIA_TYPE_JSON]: (buf) => {
|
|
84
|
+
return buf
|
|
85
|
+
},
|
|
86
|
+
[MEDIA_TYPE_RAW]: (buf) => {
|
|
87
|
+
return buf
|
|
88
|
+
},
|
|
89
|
+
[MEDIA_TYPE_OCTET_STREAM]: (buf) => {
|
|
90
|
+
return buf
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
[dagPb.code]: {
|
|
94
|
+
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
95
|
+
return dagCbor.encode(dagPb.decode(buf))
|
|
96
|
+
},
|
|
97
|
+
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
98
|
+
return dagCbor.encode(dagPb.decode(buf))
|
|
99
|
+
},
|
|
100
|
+
[MEDIA_TYPE_JSON]: (buf) => {
|
|
101
|
+
return dagJson.encode(dagPb.decode(buf))
|
|
102
|
+
},
|
|
103
|
+
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
104
|
+
return dagJson.encode(dagPb.decode(buf))
|
|
105
|
+
},
|
|
106
|
+
[MEDIA_TYPE_RAW]: (buf) => {
|
|
107
|
+
return buf
|
|
108
|
+
},
|
|
109
|
+
[MEDIA_TYPE_OCTET_STREAM]: (buf) => {
|
|
110
|
+
return buf
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
[raw.code]: {
|
|
114
|
+
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
115
|
+
return dagCbor.encode(buf)
|
|
116
|
+
},
|
|
117
|
+
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
118
|
+
return dagCbor.encode(buf)
|
|
119
|
+
},
|
|
120
|
+
[MEDIA_TYPE_JSON]: (buf) => {
|
|
121
|
+
return buf
|
|
122
|
+
},
|
|
123
|
+
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
124
|
+
return dagJson.encode(buf)
|
|
125
|
+
},
|
|
126
|
+
[MEDIA_TYPE_RAW]: (buf) => {
|
|
127
|
+
return buf
|
|
128
|
+
},
|
|
129
|
+
[MEDIA_TYPE_OCTET_STREAM]: (buf) => {
|
|
130
|
+
return buf
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
[identity.code]: {
|
|
134
|
+
[MEDIA_TYPE_CBOR]: (buf) => {
|
|
135
|
+
return dagCbor.encode(buf)
|
|
136
|
+
},
|
|
137
|
+
[MEDIA_TYPE_DAG_CBOR]: (buf) => {
|
|
138
|
+
return dagCbor.encode(buf)
|
|
139
|
+
},
|
|
140
|
+
[MEDIA_TYPE_JSON]: (buf) => {
|
|
141
|
+
return dagJson.encode(buf)
|
|
142
|
+
},
|
|
143
|
+
[MEDIA_TYPE_DAG_JSON]: (buf) => {
|
|
144
|
+
return dagJson.encode(buf)
|
|
145
|
+
},
|
|
146
|
+
[MEDIA_TYPE_RAW]: (buf) => {
|
|
147
|
+
return buf
|
|
148
|
+
},
|
|
149
|
+
[MEDIA_TYPE_OCTET_STREAM]: (buf) => {
|
|
150
|
+
return buf
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface ConvertedOutput {
|
|
156
|
+
block: Uint8Array
|
|
157
|
+
contentType: string
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Where supported, deserialize the passed block using the codec appropriate for
|
|
162
|
+
* the CID, then loop over the acceptable content types and attempt to convert
|
|
163
|
+
* the deserialized value to that format and serialize it back to a block -
|
|
164
|
+
* return the first successful result.
|
|
165
|
+
*/
|
|
166
|
+
export function convertOutput (cid: CID, block: Uint8Array, accept: AcceptHeader[]): { contentType: ContentType, output: Uint8Array } {
|
|
167
|
+
if (accept.length === 0) {
|
|
168
|
+
// return current format
|
|
169
|
+
return {
|
|
170
|
+
contentType: getContentTypesForCid(cid)[0],
|
|
171
|
+
output: block
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
for (const format of accept) {
|
|
176
|
+
const converter = CONVERSIONS[cid.code]?.[format.contentType.mediaType]
|
|
177
|
+
|
|
178
|
+
if (converter != null) {
|
|
179
|
+
return {
|
|
180
|
+
contentType: format.contentType,
|
|
181
|
+
output: converter(block)
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
throw new Error(`Could not convert ${cid} to any of ${accept.map(a => a.contentType.mediaType).join(', ')}`)
|
|
187
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { CONTENT_TYPE_OCTET_STREAM, CONTENT_TYPE_RAW } from './content-types.ts'
|
|
2
|
+
import { badGatewayResponse, gatewayTimeoutResponse, internalServerErrorResponse, notAcceptableResponse, notFoundResponse, preconditionFailedResponse } from './responses.js'
|
|
3
|
+
import type { Resource } from '../index.js'
|
|
4
|
+
|
|
5
|
+
export function errorToResponse (resource: Resource | string, err: any): Response {
|
|
6
|
+
// if a signal abort caused the error, throw the error
|
|
7
|
+
if (err.name === 'AbortError') {
|
|
8
|
+
throw err
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
// could not reach an upstream server, bad connection or offline
|
|
12
|
+
if (err.code === 'ECONNREFUSED' || err.code === 'ECANCELLED' || err.name === 'DNSQueryFailedError') {
|
|
13
|
+
return badGatewayResponse(resource.toString(), err)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// data was not parseable, user may be able to request raw block
|
|
17
|
+
if (['NotUnixFSError'].includes(err.name)) {
|
|
18
|
+
return notAcceptableResponse(resource.toString(), [
|
|
19
|
+
CONTENT_TYPE_RAW,
|
|
20
|
+
CONTENT_TYPE_OCTET_STREAM
|
|
21
|
+
])
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// an upstream server didn't respond in time but inside the signal timeout
|
|
25
|
+
if (err.code === 'ETIMEOUT' || err.name === 'TimeoutError') {
|
|
26
|
+
return gatewayTimeoutResponse(resource.toString(), err)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// path was not under DAG root
|
|
30
|
+
if (['ERR_NO_PROP', 'ERR_NO_TERMINAL_ELEMENT', 'ERR_NOT_FOUND'].includes(err.code)) {
|
|
31
|
+
return notFoundResponse(resource.toString())
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// path was not under DAG root
|
|
35
|
+
if (['DoesNotExistError'].includes(err.name)) {
|
|
36
|
+
return notFoundResponse(resource.toString())
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (['BlockNotFoundWhileOfflineError'].includes(err.name)) {
|
|
40
|
+
return preconditionFailedResponse(resource.toString())
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (['RecordNotFoundError'].includes('err.name')) {
|
|
44
|
+
return badGatewayResponse(resource.toString(), err)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// can't tell what went wrong, return a generic error
|
|
48
|
+
return internalServerErrorResponse(resource.toString(), err)
|
|
49
|
+
}
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
+
import { InvalidParametersError } from '@libp2p/interface'
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Takes a filename URL param and returns a string for use in a
|
|
3
5
|
* `Content-Disposition` header
|
|
4
6
|
*/
|
|
5
|
-
export function getContentDispositionFilename (filename: string): string {
|
|
7
|
+
export function getContentDispositionFilename (filename: string | null): string {
|
|
8
|
+
if (filename == null) {
|
|
9
|
+
throw new InvalidParametersError('Cannot get filename for Content-Disposition header - filename argument was missing')
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
const asciiOnly = replaceNonAsciiCharacters(filename)
|
|
7
13
|
|
|
8
14
|
if (asciiOnly === filename) {
|
package/src/utils/get-e-tag.ts
CHANGED
|
@@ -1,56 +1,47 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { ContentType } from '../index.ts'
|
|
2
2
|
import type { CID } from 'multiformats/cid'
|
|
3
3
|
|
|
4
4
|
interface GetETagArg {
|
|
5
|
-
cid: CID
|
|
6
|
-
reqFormat?: RequestFormatShorthand
|
|
7
|
-
rangeStart?: number
|
|
8
|
-
rangeEnd?: number
|
|
9
5
|
/**
|
|
10
|
-
*
|
|
11
|
-
* Some examples:
|
|
12
|
-
* - IPNS requests
|
|
13
|
-
* - CAR streamed with blocks in non-deterministic order
|
|
14
|
-
* - TAR streamed with files in non-deterministic order
|
|
6
|
+
* The CID that was resolved to the content in the response
|
|
15
7
|
*/
|
|
16
|
-
|
|
8
|
+
cid: CID
|
|
17
9
|
|
|
18
10
|
/**
|
|
19
|
-
*
|
|
11
|
+
* The content type of the response
|
|
20
12
|
*/
|
|
21
|
-
|
|
22
|
-
}
|
|
13
|
+
contentType: ContentType
|
|
23
14
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
return ''
|
|
29
|
-
}
|
|
15
|
+
/**
|
|
16
|
+
* Where the byte range starts, if specified
|
|
17
|
+
*/
|
|
18
|
+
rangeStart?: number
|
|
30
19
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (reqFormat === 'tar') {
|
|
36
|
-
return '.x-tar'
|
|
37
|
-
}
|
|
20
|
+
/**
|
|
21
|
+
* Where the byte range ends, if specified
|
|
22
|
+
*/
|
|
23
|
+
rangeEnd?: number
|
|
38
24
|
|
|
39
|
-
|
|
25
|
+
/**
|
|
26
|
+
* A custom prefix to use for the content of the etag
|
|
27
|
+
*/
|
|
28
|
+
contentPrefix?: string
|
|
40
29
|
}
|
|
41
30
|
|
|
42
31
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
32
|
+
* We use strong Etags for immutable responses and weak ones (prefixed with W/ )
|
|
33
|
+
* for mutable/generated ones (ipns, car, tar, and generated HTML).
|
|
34
|
+
*
|
|
35
|
+
* Block and car responses should have different etags to deserialized ones, so
|
|
36
|
+
* you can add a prefix like we do in the existing gateway.
|
|
47
37
|
*
|
|
48
38
|
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag
|
|
49
39
|
* @see https://specs.ipfs.tech/http-gateways/path-gateway/#etag-response-header
|
|
50
40
|
*/
|
|
51
|
-
export function getETag ({ cid,
|
|
52
|
-
const prefix =
|
|
53
|
-
let suffix =
|
|
41
|
+
export function getETag ({ cid, contentType, rangeStart, rangeEnd, contentPrefix }: GetETagArg): string {
|
|
42
|
+
const prefix = contentType.immutable ? '' : 'W/'
|
|
43
|
+
let suffix = contentType.etag
|
|
44
|
+
|
|
54
45
|
if (rangeStart != null || rangeEnd != null) {
|
|
55
46
|
suffix += `.${rangeStart ?? '0'}-${rangeEnd ?? 'N'}`
|
|
56
47
|
}
|
|
@@ -1,25 +1,79 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { InvalidRangeError } from '../errors.ts'
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
3
|
+
interface OffsetLength<T = number> {
|
|
4
|
+
offset: T
|
|
5
|
+
length: T
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
function downCast ({ offset, length }: OffsetLength<bigint>): OffsetLength {
|
|
9
|
+
return {
|
|
10
|
+
offset: Number(offset),
|
|
11
|
+
length: Number(length)
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* N.b. Range start (zero indexed, inclusive) and end (inclusive) - this is
|
|
17
|
+
* different to `Uint8Array.subarray` which is end exclusive.
|
|
18
|
+
*/
|
|
19
|
+
export function rangeToOffsetAndLength (size: bigint | number, start?: number | bigint, end?: number | bigint): { offset: number, length: number } {
|
|
20
|
+
size = BigInt(size)
|
|
21
|
+
|
|
22
|
+
if (start != null) {
|
|
23
|
+
start = BigInt(start)
|
|
24
|
+
|
|
25
|
+
if (start < 0n) {
|
|
26
|
+
throw new InvalidRangeError('Range start cannot be negative')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (start >= size) {
|
|
30
|
+
throw new InvalidRangeError('Range start cannot be larger than total bytes')
|
|
8
31
|
}
|
|
9
32
|
}
|
|
10
33
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const end = parts[1] === '*' ? Infinity : parseInt(parts[1], 10)
|
|
34
|
+
if (end != null) {
|
|
35
|
+
end = BigInt(end)
|
|
14
36
|
|
|
15
|
-
|
|
16
|
-
|
|
37
|
+
const abs = end > 0n ? end : -end
|
|
38
|
+
|
|
39
|
+
if (abs >= size) {
|
|
40
|
+
throw new InvalidRangeError('Range end cannot be larger than total bytes')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (end < 0n) {
|
|
44
|
+
if (start == null) {
|
|
45
|
+
start = size + end
|
|
46
|
+
end = size - 1n
|
|
47
|
+
} else {
|
|
48
|
+
throw new InvalidRangeError('Range end cannot be negative')
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// make inclusive end exclusive
|
|
53
|
+
end += 1n
|
|
17
54
|
}
|
|
18
55
|
|
|
19
|
-
|
|
56
|
+
return downCast(toOffsetAndLength(size, start, end))
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Translate `from:to` zero-indexed inclusive bytes to offset/length
|
|
61
|
+
*/
|
|
62
|
+
export function entityBytesToOffsetAndLength (size: number | bigint, entityBytes?: string | null): { offset: number, length: number } {
|
|
63
|
+
size = BigInt(size)
|
|
64
|
+
const parts = (entityBytes ?? '0:*').split(':')
|
|
65
|
+
const start = BigInt(parts[0])
|
|
66
|
+
const end = parts[1] === '*' ? size : BigInt(parts[1])
|
|
67
|
+
|
|
68
|
+
return downCast(toOffsetAndLength(size, start, end))
|
|
69
|
+
}
|
|
20
70
|
|
|
21
|
-
|
|
22
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Translate `from:to` zero-indexed inclusive bytes to offset/length
|
|
73
|
+
*/
|
|
74
|
+
function toOffsetAndLength (size: bigint, start: bigint = 0n, end: bigint = size): { offset: bigint, length: bigint } {
|
|
75
|
+
if (start >= 0n) {
|
|
76
|
+
if (end >= 0n) {
|
|
23
77
|
return {
|
|
24
78
|
offset: start,
|
|
25
79
|
length: end - start
|
|
@@ -27,28 +81,28 @@ export function getOffsetAndLength (entry: UnixFSEntry, entityBytes?: string): {
|
|
|
27
81
|
} else {
|
|
28
82
|
return {
|
|
29
83
|
offset: start,
|
|
30
|
-
length: (
|
|
84
|
+
length: (size - start) + end
|
|
31
85
|
}
|
|
32
86
|
}
|
|
33
87
|
}
|
|
34
88
|
|
|
35
89
|
// start < 0
|
|
36
|
-
let offset =
|
|
90
|
+
let offset = size + start
|
|
37
91
|
|
|
38
|
-
if (Math.abs(start) >
|
|
39
|
-
offset =
|
|
92
|
+
if (Math.abs(Number(start)) > Number(size)) {
|
|
93
|
+
offset = 0n
|
|
40
94
|
}
|
|
41
95
|
|
|
42
|
-
if (end >=
|
|
96
|
+
if (end >= 0n) {
|
|
43
97
|
return {
|
|
44
98
|
offset,
|
|
45
|
-
length:
|
|
99
|
+
length: end - offset
|
|
46
100
|
}
|
|
47
101
|
}
|
|
48
102
|
|
|
49
103
|
// end < 0
|
|
50
104
|
return {
|
|
51
105
|
offset,
|
|
52
|
-
length: (
|
|
106
|
+
length: (size - offset) + end
|
|
53
107
|
}
|
|
54
108
|
}
|