@helia/verified-fetch 0.0.0-28d62f7
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/LICENSE +4 -0
- package/README.md +531 -0
- package/dist/index.min.js +118 -0
- package/dist/src/index.d.ts +539 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +505 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/singleton.d.ts +3 -0
- package/dist/src/singleton.d.ts.map +1 -0
- package/dist/src/singleton.js +15 -0
- package/dist/src/singleton.js.map +1 -0
- package/dist/src/types.d.ts +2 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/dag-cbor-to-safe-json.d.ts +7 -0
- package/dist/src/utils/dag-cbor-to-safe-json.d.ts.map +1 -0
- package/dist/src/utils/dag-cbor-to-safe-json.js +37 -0
- package/dist/src/utils/dag-cbor-to-safe-json.js.map +1 -0
- 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/get-e-tag.d.ts +28 -0
- package/dist/src/utils/get-e-tag.d.ts.map +1 -0
- package/dist/src/utils/get-e-tag.js +18 -0
- package/dist/src/utils/get-e-tag.js.map +1 -0
- package/dist/src/utils/get-stream-from-async-iterable.d.ts +10 -0
- package/dist/src/utils/get-stream-from-async-iterable.d.ts.map +1 -0
- package/dist/src/utils/get-stream-from-async-iterable.js +38 -0
- package/dist/src/utils/get-stream-from-async-iterable.js.map +1 -0
- package/dist/src/utils/get-tar-stream.d.ts +4 -0
- package/dist/src/utils/get-tar-stream.d.ts.map +1 -0
- package/dist/src/utils/get-tar-stream.js +46 -0
- package/dist/src/utils/get-tar-stream.js.map +1 -0
- package/dist/src/utils/parse-resource.d.ts +18 -0
- package/dist/src/utils/parse-resource.d.ts.map +1 -0
- package/dist/src/utils/parse-resource.js +24 -0
- package/dist/src/utils/parse-resource.js.map +1 -0
- package/dist/src/utils/parse-url-string.d.ts +32 -0
- package/dist/src/utils/parse-url-string.d.ts.map +1 -0
- package/dist/src/utils/parse-url-string.js +115 -0
- package/dist/src/utils/parse-url-string.js.map +1 -0
- package/dist/src/utils/responses.d.ts +5 -0
- package/dist/src/utils/responses.d.ts.map +1 -0
- package/dist/src/utils/responses.js +27 -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 +148 -0
- package/dist/src/utils/select-output-type.js.map +1 -0
- package/dist/src/utils/tlru.d.ts +15 -0
- package/dist/src/utils/tlru.d.ts.map +1 -0
- package/dist/src/utils/tlru.js +40 -0
- package/dist/src/utils/tlru.js.map +1 -0
- package/dist/src/utils/walk-path.d.ts +13 -0
- package/dist/src/utils/walk-path.d.ts.map +1 -0
- package/dist/src/utils/walk-path.js +17 -0
- package/dist/src/utils/walk-path.js.map +1 -0
- package/dist/src/verified-fetch.d.ts +59 -0
- package/dist/src/verified-fetch.d.ts.map +1 -0
- package/dist/src/verified-fetch.js +408 -0
- package/dist/src/verified-fetch.js.map +1 -0
- package/package.json +197 -0
- package/src/index.ts +596 -0
- package/src/singleton.ts +20 -0
- package/src/types.ts +1 -0
- package/src/utils/dag-cbor-to-safe-json.ts +44 -0
- package/src/utils/get-content-disposition-filename.ts +18 -0
- package/src/utils/get-e-tag.ts +36 -0
- package/src/utils/get-stream-from-async-iterable.ts +45 -0
- package/src/utils/get-tar-stream.ts +68 -0
- package/src/utils/parse-resource.ts +40 -0
- package/src/utils/parse-url-string.ts +154 -0
- package/src/utils/responses.ts +29 -0
- package/src/utils/select-output-type.ts +167 -0
- package/src/utils/tlru.ts +52 -0
- package/src/utils/walk-path.ts +34 -0
- package/src/verified-fetch.ts +509 -0
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import hashlru from 'hashlru';
|
|
2
|
+
/**
|
|
3
|
+
* Time Aware Least Recent Used Cache
|
|
4
|
+
*
|
|
5
|
+
* @see https://arxiv.org/pdf/1801.00390
|
|
6
|
+
*/
|
|
7
|
+
export class TLRU {
|
|
8
|
+
lru;
|
|
9
|
+
constructor(maxSize) {
|
|
10
|
+
this.lru = hashlru(maxSize);
|
|
11
|
+
}
|
|
12
|
+
get(key) {
|
|
13
|
+
const value = this.lru.get(key);
|
|
14
|
+
if (value != null) {
|
|
15
|
+
if (value.expire != null && value.expire < Date.now()) {
|
|
16
|
+
this.lru.remove(key);
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
return value.value;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
set(key, value, ttl) {
|
|
24
|
+
this.lru.set(key, { value, expire: Date.now() + ttl });
|
|
25
|
+
}
|
|
26
|
+
has(key) {
|
|
27
|
+
const value = this.get(key);
|
|
28
|
+
if (value != null) {
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
remove(key) {
|
|
34
|
+
this.lru.remove(key);
|
|
35
|
+
}
|
|
36
|
+
clear() {
|
|
37
|
+
this.lru.clear();
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=tlru.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tlru.js","sourceRoot":"","sources":["../../../src/utils/tlru.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAA;AAE7B;;;;GAIG;AACH,MAAM,OAAO,IAAI;IACE,GAAG,CAA4B;IAEhD,YAAa,OAAe;QAC1B,IAAI,CAAC,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7B,CAAC;IAED,GAAG,CAAE,GAAW;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAE/B,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,IAAI,KAAK,CAAC,MAAM,IAAI,IAAI,IAAI,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;gBACtD,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBAEpB,OAAO,SAAS,CAAA;YAClB,CAAC;YAED,OAAO,KAAK,CAAC,KAAK,CAAA;QACpB,CAAC;QAED,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,GAAG,CAAE,GAAW,EAAE,KAAQ,EAAE,GAAW;QACrC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,GAAG,EAAE,CAAC,CAAA;IACxD,CAAC;IAED,GAAG,CAAE,GAAW;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QAE3B,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAA;QACb,CAAC;QAED,OAAO,KAAK,CAAA;IACd,CAAC;IAED,MAAM,CAAE,GAAW;QACjB,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IACtB,CAAC;IAED,KAAK;QACH,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAA;IAClB,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { type ExporterOptions, type ReadableStorage, type UnixFSEntry } from 'ipfs-unixfs-exporter';
|
|
2
|
+
import type { CID } from 'multiformats/cid';
|
|
3
|
+
export interface PathWalkerOptions extends ExporterOptions {
|
|
4
|
+
}
|
|
5
|
+
export interface PathWalkerResponse {
|
|
6
|
+
ipfsRoots: CID[];
|
|
7
|
+
terminalElement: UnixFSEntry;
|
|
8
|
+
}
|
|
9
|
+
export interface PathWalkerFn {
|
|
10
|
+
(blockstore: ReadableStorage, path: string, options?: PathWalkerOptions): Promise<PathWalkerResponse>;
|
|
11
|
+
}
|
|
12
|
+
export declare function walkPath(blockstore: ReadableStorage, path: string, options?: PathWalkerOptions): Promise<PathWalkerResponse>;
|
|
13
|
+
//# sourceMappingURL=walk-path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-path.d.ts","sourceRoot":"","sources":["../../../src/utils/walk-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4B,KAAK,eAAe,EAAE,KAAK,eAAe,EAAE,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAA;AAC7H,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAE3C,MAAM,WAAW,iBAAkB,SAAQ,eAAe;CAEzD;AACD,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,GAAG,EAAE,CAAA;IAChB,eAAe,EAAE,WAAW,CAAA;CAE7B;AAED,MAAM,WAAW,YAAY;IAC3B,CAAC,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAA;CACtG;AAED,wBAAsB,QAAQ,CAAE,UAAU,EAAE,eAAe,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAiBnI"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { walkPath as exporterWalk } from 'ipfs-unixfs-exporter';
|
|
2
|
+
export async function walkPath(blockstore, path, options) {
|
|
3
|
+
const ipfsRoots = [];
|
|
4
|
+
let terminalElement;
|
|
5
|
+
for await (const entry of exporterWalk(path, blockstore, options)) {
|
|
6
|
+
ipfsRoots.push(entry.cid);
|
|
7
|
+
terminalElement = entry;
|
|
8
|
+
}
|
|
9
|
+
if (terminalElement == null) {
|
|
10
|
+
throw new Error('No terminal element found');
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
ipfsRoots,
|
|
14
|
+
terminalElement
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=walk-path.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk-path.js","sourceRoot":"","sources":["../../../src/utils/walk-path.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAgE,MAAM,sBAAsB,CAAA;AAgB7H,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAE,UAA2B,EAAE,IAAY,EAAE,OAA2B;IACpG,MAAM,SAAS,GAAU,EAAE,CAAA;IAC3B,IAAI,eAAwC,CAAA;IAE5C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,OAAO,CAAC,EAAE,CAAC;QAClE,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACzB,eAAe,GAAG,KAAK,CAAA;IACzB,CAAC;IAED,IAAI,eAAe,IAAI,IAAI,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAA;IAC9C,CAAC;IAED,OAAO;QACL,SAAS;QACT,eAAe;KAChB,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { type IPNS } from '@helia/ipns';
|
|
2
|
+
import { type UnixFS as HeliaUnixFs } from '@helia/unixfs';
|
|
3
|
+
import type { ContentTypeParser, Resource, VerifiedFetchInit as VerifiedFetchOptions } from './index.js';
|
|
4
|
+
import type { Helia } from '@helia/interface';
|
|
5
|
+
interface VerifiedFetchComponents {
|
|
6
|
+
helia: Helia;
|
|
7
|
+
ipns?: IPNS;
|
|
8
|
+
unixfs?: HeliaUnixFs;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Potential future options for the VerifiedFetch constructor.
|
|
12
|
+
*/
|
|
13
|
+
interface VerifiedFetchInit {
|
|
14
|
+
contentTypeParser?: ContentTypeParser;
|
|
15
|
+
}
|
|
16
|
+
export declare class VerifiedFetch {
|
|
17
|
+
private readonly helia;
|
|
18
|
+
private readonly ipns;
|
|
19
|
+
private readonly unixfs;
|
|
20
|
+
private readonly log;
|
|
21
|
+
private readonly contentTypeParser;
|
|
22
|
+
constructor({ helia, ipns, unixfs }: VerifiedFetchComponents, init?: VerifiedFetchInit);
|
|
23
|
+
/**
|
|
24
|
+
* Accepts an `ipns://...` URL as a string and returns a `Response` containing
|
|
25
|
+
* a raw IPNS record.
|
|
26
|
+
*/
|
|
27
|
+
private handleIPNSRecord;
|
|
28
|
+
/**
|
|
29
|
+
* Accepts a `CID` and returns a `Response` with a body stream that is a CAR
|
|
30
|
+
* of the `DAG` referenced by the `CID`.
|
|
31
|
+
*/
|
|
32
|
+
private handleCar;
|
|
33
|
+
/**
|
|
34
|
+
* Accepts a UnixFS `CID` and returns a `.tar` file containing the file or
|
|
35
|
+
* directory structure referenced by the `CID`.
|
|
36
|
+
*/
|
|
37
|
+
private handleTar;
|
|
38
|
+
private handleJson;
|
|
39
|
+
private handleDagCbor;
|
|
40
|
+
private handleDagPb;
|
|
41
|
+
private handleRaw;
|
|
42
|
+
private setContentType;
|
|
43
|
+
/**
|
|
44
|
+
* If the user has not specified an Accept header or format query string arg,
|
|
45
|
+
* use the CID codec to choose an appropriate handler for the block data.
|
|
46
|
+
*/
|
|
47
|
+
private readonly codecHandlers;
|
|
48
|
+
fetch(resource: Resource, opts?: VerifiedFetchOptions): Promise<Response>;
|
|
49
|
+
/**
|
|
50
|
+
* Start the Helia instance
|
|
51
|
+
*/
|
|
52
|
+
start(): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Shut down the Helia instance
|
|
55
|
+
*/
|
|
56
|
+
stop(): Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
export {};
|
|
59
|
+
//# sourceMappingURL=verified-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verified-fetch.d.ts","sourceRoot":"","sources":["../../src/verified-fetch.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,KAAK,IAAI,EAAE,MAAM,aAAa,CAAA;AAE1D,OAAO,EAAyB,KAAK,MAAM,IAAI,WAAW,EAAoB,MAAM,eAAe,CAAA;AAwBnG,OAAO,KAAK,EAAa,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,IAAI,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAEnH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAK7C,UAAU,uBAAuB;IAC/B,KAAK,EAAE,KAAK,CAAA;IACZ,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,MAAM,CAAC,EAAE,WAAW,CAAA;CACrB;AAED;;GAEG;AACH,UAAU,iBAAiB;IACzB,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;CACtC;AAwED,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAO;IAC7B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAM;IAC3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA+B;gBAEpD,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,uBAAuB,EAAE,IAAI,CAAC,EAAE,iBAAiB;IAcvF;;;OAGG;YACW,gBAAgB;IAgC9B;;;OAGG;YACW,SAAS;IAUvB;;;OAGG;YACW,SAAS;YAaT,UAAU;YA0BV,aAAa;YA8Cb,WAAW;YAwDX,SAAS;YAiBT,cAAc;IA0B5B;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAO7B;IAEK,KAAK,CAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,QAAQ,CAAC;IAsGhF;;OAEG;IACG,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAI7B;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -0,0 +1,408 @@
|
|
|
1
|
+
import { car } from '@helia/car';
|
|
2
|
+
import { ipns as heliaIpns } from '@helia/ipns';
|
|
3
|
+
import { dnsJsonOverHttps } from '@helia/ipns/dns-resolvers';
|
|
4
|
+
import { unixfs as heliaUnixFs } from '@helia/unixfs';
|
|
5
|
+
import * as ipldDagCbor from '@ipld/dag-cbor';
|
|
6
|
+
import * as ipldDagJson from '@ipld/dag-json';
|
|
7
|
+
import { code as dagPbCode } from '@ipld/dag-pb';
|
|
8
|
+
import { Record as DHTRecord } from '@libp2p/kad-dht';
|
|
9
|
+
import { peerIdFromString } from '@libp2p/peer-id';
|
|
10
|
+
import { Key } from 'interface-datastore';
|
|
11
|
+
import toBrowserReadableStream from 'it-to-browser-readablestream';
|
|
12
|
+
import { code as jsonCode } from 'multiformats/codecs/json';
|
|
13
|
+
import { code as rawCode } from 'multiformats/codecs/raw';
|
|
14
|
+
import { identity } from 'multiformats/hashes/identity';
|
|
15
|
+
import { CustomProgressEvent } from 'progress-events';
|
|
16
|
+
import { concat as uint8ArrayConcat } from 'uint8arrays/concat';
|
|
17
|
+
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string';
|
|
18
|
+
import { toString as uint8ArrayToString } from 'uint8arrays/to-string';
|
|
19
|
+
import { dagCborToSafeJSON } from './utils/dag-cbor-to-safe-json.js';
|
|
20
|
+
import { getContentDispositionFilename } from './utils/get-content-disposition-filename.js';
|
|
21
|
+
import { getETag } from './utils/get-e-tag.js';
|
|
22
|
+
import { getStreamFromAsyncIterable } from './utils/get-stream-from-async-iterable.js';
|
|
23
|
+
import { tarStream } from './utils/get-tar-stream.js';
|
|
24
|
+
import { parseResource } from './utils/parse-resource.js';
|
|
25
|
+
import { badRequestResponse, notAcceptableResponse, notSupportedResponse, okResponse } from './utils/responses.js';
|
|
26
|
+
import { selectOutputType, queryFormatToAcceptHeader } from './utils/select-output-type.js';
|
|
27
|
+
import { walkPath } from './utils/walk-path.js';
|
|
28
|
+
function convertOptions(options) {
|
|
29
|
+
if (options == null) {
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
let signal;
|
|
33
|
+
if (options?.signal === null) {
|
|
34
|
+
signal = undefined;
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
...options,
|
|
38
|
+
signal
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* These are Accept header values that will cause content type sniffing to be
|
|
43
|
+
* skipped and set to these values.
|
|
44
|
+
*/
|
|
45
|
+
const RAW_HEADERS = [
|
|
46
|
+
'application/vnd.ipld.raw',
|
|
47
|
+
'application/octet-stream'
|
|
48
|
+
];
|
|
49
|
+
/**
|
|
50
|
+
* if the user has specified an `Accept` header, and it's in our list of
|
|
51
|
+
* allowable "raw" format headers, use that instead of detecting the content
|
|
52
|
+
* type. This avoids the user from receiving something different when they
|
|
53
|
+
* signal that they want to `Accept` a specific mime type.
|
|
54
|
+
*/
|
|
55
|
+
function getOverridenRawContentType(headers) {
|
|
56
|
+
const acceptHeader = new Headers(headers).get('accept') ?? '';
|
|
57
|
+
// e.g. "Accept: text/html, application/xhtml+xml, application/xml;q=0.9, image/webp, */*;q=0.8"
|
|
58
|
+
const acceptHeaders = acceptHeader.split(',')
|
|
59
|
+
.map(s => s.split(';')[0])
|
|
60
|
+
.map(s => s.trim());
|
|
61
|
+
for (const mimeType of acceptHeaders) {
|
|
62
|
+
if (mimeType === '*/*') {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
if (RAW_HEADERS.includes(mimeType ?? '')) {
|
|
66
|
+
return mimeType;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export class VerifiedFetch {
|
|
71
|
+
helia;
|
|
72
|
+
ipns;
|
|
73
|
+
unixfs;
|
|
74
|
+
log;
|
|
75
|
+
contentTypeParser;
|
|
76
|
+
constructor({ helia, ipns, unixfs }, init) {
|
|
77
|
+
this.helia = helia;
|
|
78
|
+
this.log = helia.logger.forComponent('helia:verified-fetch');
|
|
79
|
+
this.ipns = ipns ?? heliaIpns(helia, {
|
|
80
|
+
resolvers: [
|
|
81
|
+
dnsJsonOverHttps('https://mozilla.cloudflare-dns.com/dns-query'),
|
|
82
|
+
dnsJsonOverHttps('https://dns.google/resolve')
|
|
83
|
+
]
|
|
84
|
+
});
|
|
85
|
+
this.unixfs = unixfs ?? heliaUnixFs(helia);
|
|
86
|
+
this.contentTypeParser = init?.contentTypeParser;
|
|
87
|
+
this.log.trace('created VerifiedFetch instance');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Accepts an `ipns://...` URL as a string and returns a `Response` containing
|
|
91
|
+
* a raw IPNS record.
|
|
92
|
+
*/
|
|
93
|
+
async handleIPNSRecord({ resource, cid, path, options }) {
|
|
94
|
+
if (path !== '' || !resource.startsWith('ipns://')) {
|
|
95
|
+
return badRequestResponse('Invalid IPNS name');
|
|
96
|
+
}
|
|
97
|
+
let peerId;
|
|
98
|
+
try {
|
|
99
|
+
peerId = peerIdFromString(resource.replace('ipns://', ''));
|
|
100
|
+
}
|
|
101
|
+
catch (err) {
|
|
102
|
+
this.log.error('could not parse peer id from IPNS url %s', resource);
|
|
103
|
+
return badRequestResponse('Invalid IPNS name');
|
|
104
|
+
}
|
|
105
|
+
// since this call happens after parseResource, we've already resolved the
|
|
106
|
+
// IPNS name so a local copy should be in the helia datastore, so we can
|
|
107
|
+
// just read it out..
|
|
108
|
+
const routingKey = uint8ArrayConcat([
|
|
109
|
+
uint8ArrayFromString('/ipns/'),
|
|
110
|
+
peerId.toBytes()
|
|
111
|
+
]);
|
|
112
|
+
const datastoreKey = new Key('/dht/record/' + uint8ArrayToString(routingKey, 'base32'), false);
|
|
113
|
+
const buf = await this.helia.datastore.get(datastoreKey, options);
|
|
114
|
+
const record = DHTRecord.deserialize(buf);
|
|
115
|
+
const response = okResponse(record.value);
|
|
116
|
+
response.headers.set('content-type', 'application/vnd.ipfs.ipns-record');
|
|
117
|
+
return response;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Accepts a `CID` and returns a `Response` with a body stream that is a CAR
|
|
121
|
+
* of the `DAG` referenced by the `CID`.
|
|
122
|
+
*/
|
|
123
|
+
async handleCar({ cid, options }) {
|
|
124
|
+
const c = car(this.helia);
|
|
125
|
+
const stream = toBrowserReadableStream(c.stream(cid, options));
|
|
126
|
+
const response = okResponse(stream);
|
|
127
|
+
response.headers.set('content-type', 'application/vnd.ipld.car; version=1');
|
|
128
|
+
return response;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Accepts a UnixFS `CID` and returns a `.tar` file containing the file or
|
|
132
|
+
* directory structure referenced by the `CID`.
|
|
133
|
+
*/
|
|
134
|
+
async handleTar({ cid, path, options }) {
|
|
135
|
+
if (cid.code !== dagPbCode && cid.code !== rawCode) {
|
|
136
|
+
return notAcceptableResponse('only UnixFS data can be returned in a TAR file');
|
|
137
|
+
}
|
|
138
|
+
const stream = toBrowserReadableStream(tarStream(`/ipfs/${cid}/${path}`, this.helia.blockstore, options));
|
|
139
|
+
const response = okResponse(stream);
|
|
140
|
+
response.headers.set('content-type', 'application/x-tar');
|
|
141
|
+
return response;
|
|
142
|
+
}
|
|
143
|
+
async handleJson({ cid, path, accept, options }) {
|
|
144
|
+
this.log.trace('fetching %c/%s', cid, path);
|
|
145
|
+
const block = await this.helia.blockstore.get(cid, options);
|
|
146
|
+
let body;
|
|
147
|
+
if (accept === 'application/vnd.ipld.dag-cbor' || accept === 'application/cbor') {
|
|
148
|
+
try {
|
|
149
|
+
// if vnd.ipld.dag-cbor has been specified, convert to the format - note
|
|
150
|
+
// that this supports more data types than regular JSON, the content-type
|
|
151
|
+
// response header is set so the user knows to process it differently
|
|
152
|
+
const obj = ipldDagJson.decode(block);
|
|
153
|
+
body = ipldDagCbor.encode(obj);
|
|
154
|
+
}
|
|
155
|
+
catch (err) {
|
|
156
|
+
this.log.error('could not transform %c to application/vnd.ipld.dag-cbor', err);
|
|
157
|
+
return notAcceptableResponse();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
// skip decoding
|
|
162
|
+
body = block;
|
|
163
|
+
}
|
|
164
|
+
const response = okResponse(body);
|
|
165
|
+
response.headers.set('content-type', accept ?? 'application/json');
|
|
166
|
+
return response;
|
|
167
|
+
}
|
|
168
|
+
async handleDagCbor({ cid, path, accept, options }) {
|
|
169
|
+
this.log.trace('fetching %c/%s', cid, path);
|
|
170
|
+
const block = await this.helia.blockstore.get(cid, options);
|
|
171
|
+
let body;
|
|
172
|
+
if (accept === 'application/octet-stream' || accept === 'application/vnd.ipld.dag-cbor' || accept === 'application/cbor') {
|
|
173
|
+
// skip decoding
|
|
174
|
+
body = block;
|
|
175
|
+
}
|
|
176
|
+
else if (accept === 'application/vnd.ipld.dag-json') {
|
|
177
|
+
try {
|
|
178
|
+
// if vnd.ipld.dag-json has been specified, convert to the format - note
|
|
179
|
+
// that this supports more data types than regular JSON, the content-type
|
|
180
|
+
// response header is set so the user knows to process it differently
|
|
181
|
+
const obj = ipldDagCbor.decode(block);
|
|
182
|
+
body = ipldDagJson.encode(obj);
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
this.log.error('could not transform %c to application/vnd.ipld.dag-json', err);
|
|
186
|
+
return notAcceptableResponse();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
try {
|
|
191
|
+
body = dagCborToSafeJSON(block);
|
|
192
|
+
}
|
|
193
|
+
catch (err) {
|
|
194
|
+
if (accept === 'application/json') {
|
|
195
|
+
this.log('could not decode DAG-CBOR as JSON-safe, but the client sent "Accept: application/json"', err);
|
|
196
|
+
return notAcceptableResponse();
|
|
197
|
+
}
|
|
198
|
+
this.log('could not decode DAG-CBOR as JSON-safe, falling back to `application/octet-stream`', err);
|
|
199
|
+
body = block;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const response = okResponse(body);
|
|
203
|
+
if (accept == null) {
|
|
204
|
+
accept = body instanceof Uint8Array ? 'application/octet-stream' : 'application/json';
|
|
205
|
+
}
|
|
206
|
+
response.headers.set('content-type', accept);
|
|
207
|
+
return response;
|
|
208
|
+
}
|
|
209
|
+
async handleDagPb({ cid, path, options }) {
|
|
210
|
+
let terminalElement;
|
|
211
|
+
let ipfsRoots;
|
|
212
|
+
try {
|
|
213
|
+
const pathDetails = await walkPath(this.helia.blockstore, `${cid.toString()}/${path}`, options);
|
|
214
|
+
ipfsRoots = pathDetails.ipfsRoots;
|
|
215
|
+
terminalElement = pathDetails.terminalElement;
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
this.log.error('Error walking path %s', path, err);
|
|
219
|
+
}
|
|
220
|
+
let resolvedCID = terminalElement?.cid ?? cid;
|
|
221
|
+
let stat;
|
|
222
|
+
if (terminalElement?.type === 'directory') {
|
|
223
|
+
const dirCid = terminalElement.cid;
|
|
224
|
+
const rootFilePath = 'index.html';
|
|
225
|
+
try {
|
|
226
|
+
this.log.trace('found directory at %c/%s, looking for index.html', cid, path);
|
|
227
|
+
stat = await this.unixfs.stat(dirCid, {
|
|
228
|
+
path: rootFilePath,
|
|
229
|
+
signal: options?.signal,
|
|
230
|
+
onProgress: options?.onProgress
|
|
231
|
+
});
|
|
232
|
+
this.log.trace('found root file at %c/%s with cid %c', dirCid, rootFilePath, stat.cid);
|
|
233
|
+
path = rootFilePath;
|
|
234
|
+
resolvedCID = stat.cid;
|
|
235
|
+
// terminalElement = stat
|
|
236
|
+
}
|
|
237
|
+
catch (err) {
|
|
238
|
+
this.log('error loading path %c/%s', dirCid, rootFilePath, err);
|
|
239
|
+
return notSupportedResponse('Unable to find index.html for directory at given path. Support for directories with implicit root is not implemented');
|
|
240
|
+
}
|
|
241
|
+
finally {
|
|
242
|
+
options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid: dirCid, path: rootFilePath }));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
const asyncIter = this.unixfs.cat(resolvedCID, {
|
|
246
|
+
signal: options?.signal,
|
|
247
|
+
onProgress: options?.onProgress
|
|
248
|
+
});
|
|
249
|
+
this.log('got async iterator for %c/%s', cid, path);
|
|
250
|
+
const { stream, firstChunk } = await getStreamFromAsyncIterable(asyncIter, path ?? '', this.helia.logger, {
|
|
251
|
+
onProgress: options?.onProgress
|
|
252
|
+
});
|
|
253
|
+
const response = okResponse(stream);
|
|
254
|
+
await this.setContentType(firstChunk, path, response);
|
|
255
|
+
if (ipfsRoots != null) {
|
|
256
|
+
response.headers.set('X-Ipfs-Roots', ipfsRoots.map(cid => cid.toV1().toString()).join(',')); // https://specs.ipfs.tech/http-gateways/path-gateway/#x-ipfs-roots-response-header
|
|
257
|
+
}
|
|
258
|
+
return response;
|
|
259
|
+
}
|
|
260
|
+
async handleRaw({ cid, path, options }) {
|
|
261
|
+
const result = await this.helia.blockstore.get(cid, options);
|
|
262
|
+
const response = okResponse(result);
|
|
263
|
+
// if the user has specified an `Accept` header that corresponds to a raw
|
|
264
|
+
// type, honour that header, so for example they don't request
|
|
265
|
+
// `application/vnd.ipld.raw` but get `application/octet-stream`
|
|
266
|
+
const overriddenContentType = getOverridenRawContentType(options?.headers);
|
|
267
|
+
if (overriddenContentType != null) {
|
|
268
|
+
response.headers.set('content-type', overriddenContentType);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
await this.setContentType(result, path, response);
|
|
272
|
+
}
|
|
273
|
+
return response;
|
|
274
|
+
}
|
|
275
|
+
async setContentType(bytes, path, response) {
|
|
276
|
+
let contentType = 'application/octet-stream';
|
|
277
|
+
if (this.contentTypeParser != null) {
|
|
278
|
+
try {
|
|
279
|
+
let fileName = path.split('/').pop()?.trim();
|
|
280
|
+
fileName = fileName === '' ? undefined : fileName;
|
|
281
|
+
const parsed = this.contentTypeParser(bytes, fileName);
|
|
282
|
+
if (isPromise(parsed)) {
|
|
283
|
+
const result = await parsed;
|
|
284
|
+
if (result != null) {
|
|
285
|
+
contentType = result;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
else if (parsed != null) {
|
|
289
|
+
contentType = parsed;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
catch (err) {
|
|
293
|
+
this.log.error('Error parsing content type', err);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
response.headers.set('content-type', contentType);
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* If the user has not specified an Accept header or format query string arg,
|
|
300
|
+
* use the CID codec to choose an appropriate handler for the block data.
|
|
301
|
+
*/
|
|
302
|
+
codecHandlers = {
|
|
303
|
+
[dagPbCode]: this.handleDagPb,
|
|
304
|
+
[ipldDagJson.code]: this.handleJson,
|
|
305
|
+
[jsonCode]: this.handleJson,
|
|
306
|
+
[ipldDagCbor.code]: this.handleDagCbor,
|
|
307
|
+
[rawCode]: this.handleRaw,
|
|
308
|
+
[identity.code]: this.handleRaw
|
|
309
|
+
};
|
|
310
|
+
async fetch(resource, opts) {
|
|
311
|
+
this.log('fetch %s', resource);
|
|
312
|
+
const options = convertOptions(opts);
|
|
313
|
+
options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:start', { resource }));
|
|
314
|
+
// resolve the CID/path from the requested resource
|
|
315
|
+
const { path, query, cid } = await parseResource(resource, { ipns: this.ipns, logger: this.helia.logger }, options);
|
|
316
|
+
options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:resolve', { cid, path }));
|
|
317
|
+
const requestHeaders = new Headers(options?.headers);
|
|
318
|
+
const incomingAcceptHeader = requestHeaders.get('accept');
|
|
319
|
+
if (incomingAcceptHeader != null) {
|
|
320
|
+
this.log('incoming accept header "%s"', incomingAcceptHeader);
|
|
321
|
+
}
|
|
322
|
+
const queryFormatMapping = queryFormatToAcceptHeader(query.format);
|
|
323
|
+
if (query.format != null) {
|
|
324
|
+
this.log('incoming query format "%s", mapped to %s', query.format, queryFormatMapping);
|
|
325
|
+
}
|
|
326
|
+
const acceptHeader = incomingAcceptHeader ?? queryFormatMapping;
|
|
327
|
+
const accept = selectOutputType(cid, acceptHeader);
|
|
328
|
+
this.log('output type %s', accept);
|
|
329
|
+
if (acceptHeader != null && accept == null) {
|
|
330
|
+
return notAcceptableResponse();
|
|
331
|
+
}
|
|
332
|
+
let response;
|
|
333
|
+
let reqFormat;
|
|
334
|
+
const handlerArgs = { resource: resource.toString(), cid, path, accept, options };
|
|
335
|
+
if (accept === 'application/vnd.ipfs.ipns-record') {
|
|
336
|
+
// the user requested a raw IPNS record
|
|
337
|
+
reqFormat = 'ipns-record';
|
|
338
|
+
response = await this.handleIPNSRecord(handlerArgs);
|
|
339
|
+
}
|
|
340
|
+
else if (accept === 'application/vnd.ipld.car') {
|
|
341
|
+
// the user requested a CAR file
|
|
342
|
+
reqFormat = 'car';
|
|
343
|
+
query.download = true;
|
|
344
|
+
query.filename = query.filename ?? `${cid.toString()}.car`;
|
|
345
|
+
response = await this.handleCar(handlerArgs);
|
|
346
|
+
}
|
|
347
|
+
else if (accept === 'application/vnd.ipld.raw') {
|
|
348
|
+
// the user requested a raw block
|
|
349
|
+
reqFormat = 'raw';
|
|
350
|
+
query.download = true;
|
|
351
|
+
query.filename = query.filename ?? `${cid.toString()}.bin`;
|
|
352
|
+
response = await this.handleRaw(handlerArgs);
|
|
353
|
+
}
|
|
354
|
+
else if (accept === 'application/x-tar') {
|
|
355
|
+
// the user requested a TAR file
|
|
356
|
+
reqFormat = 'tar';
|
|
357
|
+
query.download = true;
|
|
358
|
+
query.filename = query.filename ?? `${cid.toString()}.tar`;
|
|
359
|
+
response = await this.handleTar(handlerArgs);
|
|
360
|
+
}
|
|
361
|
+
else {
|
|
362
|
+
// derive the handler from the CID type
|
|
363
|
+
const codecHandler = this.codecHandlers[cid.code];
|
|
364
|
+
if (codecHandler == null) {
|
|
365
|
+
return notSupportedResponse(`Support for codec with code ${cid.code} is not yet implemented. Please open an issue at https://github.com/ipfs/helia/issues/new`);
|
|
366
|
+
}
|
|
367
|
+
response = await codecHandler.call(this, handlerArgs);
|
|
368
|
+
}
|
|
369
|
+
response.headers.set('etag', getETag({ cid, reqFormat, weak: false }));
|
|
370
|
+
response.headers.set('cache-control', 'public, max-age=29030400, immutable');
|
|
371
|
+
// https://specs.ipfs.tech/http-gateways/path-gateway/#x-ipfs-path-response-header
|
|
372
|
+
response.headers.set('X-Ipfs-Path', resource.toString());
|
|
373
|
+
// set Content-Disposition header
|
|
374
|
+
let contentDisposition;
|
|
375
|
+
// force download if requested
|
|
376
|
+
if (query.download === true) {
|
|
377
|
+
contentDisposition = 'attachment';
|
|
378
|
+
}
|
|
379
|
+
// override filename if requested
|
|
380
|
+
if (query.filename != null) {
|
|
381
|
+
if (contentDisposition == null) {
|
|
382
|
+
contentDisposition = 'inline';
|
|
383
|
+
}
|
|
384
|
+
contentDisposition = `${contentDisposition}; ${getContentDispositionFilename(query.filename)}`;
|
|
385
|
+
}
|
|
386
|
+
if (contentDisposition != null) {
|
|
387
|
+
response.headers.set('Content-Disposition', contentDisposition);
|
|
388
|
+
}
|
|
389
|
+
options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:end', { cid, path }));
|
|
390
|
+
return response;
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Start the Helia instance
|
|
394
|
+
*/
|
|
395
|
+
async start() {
|
|
396
|
+
await this.helia.start();
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Shut down the Helia instance
|
|
400
|
+
*/
|
|
401
|
+
async stop() {
|
|
402
|
+
await this.helia.stop();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
function isPromise(p) {
|
|
406
|
+
return p?.then != null;
|
|
407
|
+
}
|
|
408
|
+
//# sourceMappingURL=verified-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"verified-fetch.js","sourceRoot":"","sources":["../../src/verified-fetch.ts"],"names":[],"mappings":"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"}
|