@helia/verified-fetch 1.2.1 → 1.3.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/dist/index.min.js +5 -5
- package/dist/src/utils/get-stream-from-async-iterable.d.ts +1 -1
- package/dist/src/utils/get-stream-from-async-iterable.d.ts.map +1 -1
- package/dist/src/utils/get-stream-from-async-iterable.js +5 -0
- package/dist/src/utils/get-stream-from-async-iterable.js.map +1 -1
- package/dist/src/utils/parse-resource.d.ts +3 -4
- package/dist/src/utils/parse-resource.d.ts.map +1 -1
- package/dist/src/utils/parse-resource.js +3 -2
- package/dist/src/utils/parse-resource.js.map +1 -1
- package/dist/src/utils/parse-url-string.d.ts +13 -8
- package/dist/src/utils/parse-url-string.d.ts.map +1 -1
- package/dist/src/utils/parse-url-string.js +62 -10
- package/dist/src/utils/parse-url-string.js.map +1 -1
- package/dist/src/utils/response-headers.d.ts +19 -0
- package/dist/src/utils/response-headers.d.ts.map +1 -1
- package/dist/src/utils/response-headers.js +25 -0
- package/dist/src/utils/response-headers.js.map +1 -1
- package/dist/src/utils/responses.d.ts +4 -1
- package/dist/src/utils/responses.d.ts.map +1 -1
- package/dist/src/utils/responses.js +6 -0
- package/dist/src/utils/responses.js.map +1 -1
- package/dist/src/verified-fetch.d.ts +12 -0
- package/dist/src/verified-fetch.d.ts.map +1 -1
- package/dist/src/verified-fetch.js +37 -5
- package/dist/src/verified-fetch.js.map +1 -1
- package/package.json +1 -1
- package/src/utils/get-stream-from-async-iterable.ts +6 -1
- package/src/utils/parse-resource.ts +7 -7
- package/src/utils/parse-url-string.ts +88 -21
- package/src/utils/response-headers.ts +36 -0
- package/src/utils/responses.ts +7 -1
- package/src/verified-fetch.ts +42 -7
|
@@ -3,7 +3,7 @@ import type { ComponentLogger } from '@libp2p/interface';
|
|
|
3
3
|
/**
|
|
4
4
|
* Converts an async iterator of Uint8Array bytes to a stream and returns the first chunk of bytes
|
|
5
5
|
*/
|
|
6
|
-
export declare function getStreamFromAsyncIterable(iterator: AsyncIterable<Uint8Array>, path: string, logger: ComponentLogger, options?: Pick<VerifiedFetchInit, 'onProgress'>): Promise<{
|
|
6
|
+
export declare function getStreamFromAsyncIterable(iterator: AsyncIterable<Uint8Array>, path: string, logger: ComponentLogger, options?: Pick<VerifiedFetchInit, 'onProgress' | 'signal'>): Promise<{
|
|
7
7
|
stream: ReadableStream<Uint8Array>;
|
|
8
8
|
firstChunk: Uint8Array;
|
|
9
9
|
}>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-stream-from-async-iterable.d.ts","sourceRoot":"","sources":["../../../src/utils/get-stream-from-async-iterable.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD;;GAEG;AACH,wBAAsB,0BAA0B,CAAE,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,CAAC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"get-stream-from-async-iterable.d.ts","sourceRoot":"","sources":["../../../src/utils/get-stream-from-async-iterable.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD;;GAEG;AACH,wBAAsB,0BAA0B,CAAE,QAAQ,EAAE,aAAa,CAAC,UAAU,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,CAAC,EAAE,IAAI,CAAC,iBAAiB,EAAE,YAAY,GAAG,QAAQ,CAAC,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IAAC,UAAU,EAAE,UAAU,CAAA;CAAE,CAAC,CA0CjQ"}
|
|
@@ -18,6 +18,11 @@ export async function getStreamFromAsyncIterable(iterator, path, logger, options
|
|
|
18
18
|
},
|
|
19
19
|
async pull(controller) {
|
|
20
20
|
const { value, done } = await reader.next();
|
|
21
|
+
if (options?.signal?.aborted === true) {
|
|
22
|
+
controller.error(new Error(options.signal.reason ?? 'signal aborted by user'));
|
|
23
|
+
controller.close();
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
21
26
|
if (done === true) {
|
|
22
27
|
if (value != null) {
|
|
23
28
|
options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:progress:chunk'));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-stream-from-async-iterable.js","sourceRoot":"","sources":["../../../src/utils/get-stream-from-async-iterable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAIrD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAE,QAAmC,EAAE,IAAY,EAAE,MAAuB,EAAE,
|
|
1
|
+
{"version":3,"file":"get-stream-from-async-iterable.js","sourceRoot":"","sources":["../../../src/utils/get-stream-from-async-iterable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAIrD;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B,CAAE,QAAmC,EAAE,IAAY,EAAE,MAAuB,EAAE,OAA0D;IACtL,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,qDAAqD,CAAC,CAAA;IACtF,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,CAAA;IAC/C,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;IAEvD,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,GAAG,CAAC,KAAK,CAAC,2BAA2B,EAAE,IAAI,CAAC,CAAA;QAC5C,MAAM,IAAI,KAAK,CAAC,kBAAkB,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,cAAc,CAAC;QAChC,KAAK,CAAC,KAAK,CAAE,UAAU;YACrB,yCAAyC;YACzC,OAAO,EAAE,UAAU,EAAE,CAAC,IAAI,mBAAmB,CAAO,uCAAuC,CAAC,CAAC,CAAA;YAC7F,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;QAChC,CAAC;QACD,KAAK,CAAC,IAAI,CAAE,UAAU;YACpB,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;YAC3C,IAAI,OAAO,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,EAAE,CAAC;gBACtC,UAAU,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,IAAI,wBAAwB,CAAC,CAAC,CAAA;gBAC9E,UAAU,CAAC,KAAK,EAAE,CAAA;gBAClB,OAAM;YACR,CAAC;YAED,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAClB,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;oBAClB,OAAO,EAAE,UAAU,EAAE,CAAC,IAAI,mBAAmB,CAAO,uCAAuC,CAAC,CAAC,CAAA;oBAC7F,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;gBAC3B,CAAC;gBACD,UAAU,CAAC,KAAK,EAAE,CAAA;gBAClB,OAAM;YACR,CAAC;YAED,OAAO,EAAE,UAAU,EAAE,CAAC,IAAI,mBAAmB,CAAO,uCAAuC,CAAC,CAAC,CAAA;YAC7F,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC3B,CAAC;KACF,CAAC,CAAA;IAEF,OAAO;QACL,MAAM;QACN,UAAU;KACX,CAAA;AACH,CAAC"}
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import type { ParsedUrlStringResults } from './parse-url-string.js';
|
|
1
|
+
import type { ParseUrlStringOptions, ParsedUrlStringResults } from './parse-url-string.js';
|
|
2
2
|
import type { Resource } from '../index.js';
|
|
3
|
-
import type { IPNS
|
|
3
|
+
import type { IPNS } from '@helia/ipns';
|
|
4
4
|
import type { ComponentLogger } from '@libp2p/interface';
|
|
5
|
-
import type { ProgressOptions } from 'progress-events';
|
|
6
5
|
export interface ParseResourceComponents {
|
|
7
6
|
ipns: IPNS;
|
|
8
7
|
logger: ComponentLogger;
|
|
9
8
|
}
|
|
10
|
-
export interface ParseResourceOptions extends
|
|
9
|
+
export interface ParseResourceOptions extends ParseUrlStringOptions {
|
|
11
10
|
}
|
|
12
11
|
/**
|
|
13
12
|
* Handles the different use cases for the `resource` argument.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-resource.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"parse-resource.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAA;AAC1F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAExD,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,oBAAqB,SAAQ,qBAAqB;CAElE;AACD;;;;GAIG;AACH,wBAAsB,aAAa,CAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,uBAAuB,EAAE,OAAO,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAmBnK"}
|
|
@@ -7,7 +7,7 @@ import { parseUrlString } from './parse-url-string.js';
|
|
|
7
7
|
*/
|
|
8
8
|
export async function parseResource(resource, { ipns, logger }, options) {
|
|
9
9
|
if (typeof resource === 'string') {
|
|
10
|
-
return parseUrlString({ urlString: resource, ipns, logger },
|
|
10
|
+
return parseUrlString({ urlString: resource, ipns, logger }, options);
|
|
11
11
|
}
|
|
12
12
|
const cid = CID.asCID(resource);
|
|
13
13
|
if (cid != null) {
|
|
@@ -16,7 +16,8 @@ export async function parseResource(resource, { ipns, logger }, options) {
|
|
|
16
16
|
cid,
|
|
17
17
|
protocol: 'ipfs',
|
|
18
18
|
path: '',
|
|
19
|
-
query: {}
|
|
19
|
+
query: {},
|
|
20
|
+
ttl: 29030400 // 1 year for ipfs content
|
|
20
21
|
};
|
|
21
22
|
}
|
|
22
23
|
throw new TypeError(`Invalid resource. Cannot determine CID from resource: ${resource}`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-resource.js","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;
|
|
1
|
+
{"version":3,"file":"parse-resource.js","sourceRoot":"","sources":["../../../src/utils/parse-resource.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AActD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAE,QAAkB,EAAE,EAAE,IAAI,EAAE,MAAM,EAA2B,EAAE,OAA8B;IAChI,IAAI,OAAO,QAAQ,KAAK,QAAQ,EAAE,CAAC;QACjC,OAAO,cAAc,CAAC,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,CAAA;IACvE,CAAC;IAED,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAA;IAE/B,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAChB,gBAAgB;QAChB,OAAO;YACL,GAAG;YACH,QAAQ,EAAE,MAAM;YAChB,IAAI,EAAE,EAAE;YACR,KAAK,EAAE,EAAE;YACT,GAAG,EAAE,QAAQ,CAAC,0BAA0B;SACR,CAAA;IACpC,CAAC;IAED,MAAM,IAAI,SAAS,CAAC,yDAAyD,QAAQ,EAAE,CAAC,CAAA;AAC1F,CAAC"}
|
|
@@ -1,32 +1,37 @@
|
|
|
1
|
-
import { CID } from 'multiformats/cid';
|
|
2
1
|
import type { RequestFormatShorthand } from '../types.js';
|
|
3
|
-
import type { IPNS, ResolveDNSLinkProgressEvents } from '@helia/ipns';
|
|
4
|
-
import type { ComponentLogger } from '@libp2p/interface';
|
|
2
|
+
import type { IPNS, IPNSRoutingEvents, ResolveDNSLinkProgressEvents, ResolveProgressEvents, ResolveResult } from '@helia/ipns';
|
|
3
|
+
import type { AbortOptions, ComponentLogger } from '@libp2p/interface';
|
|
5
4
|
import type { ProgressOptions } from 'progress-events';
|
|
6
5
|
export interface ParseUrlStringInput {
|
|
7
6
|
urlString: string;
|
|
8
7
|
ipns: IPNS;
|
|
9
8
|
logger: ComponentLogger;
|
|
10
9
|
}
|
|
11
|
-
export interface ParseUrlStringOptions extends ProgressOptions<ResolveDNSLinkProgressEvents
|
|
10
|
+
export interface ParseUrlStringOptions extends ProgressOptions<ResolveProgressEvents | IPNSRoutingEvents | ResolveDNSLinkProgressEvents>, AbortOptions {
|
|
12
11
|
}
|
|
13
12
|
export interface ParsedUrlQuery extends Record<string, string | unknown> {
|
|
14
13
|
format?: RequestFormatShorthand;
|
|
15
14
|
download?: boolean;
|
|
16
15
|
filename?: string;
|
|
17
16
|
}
|
|
18
|
-
|
|
19
|
-
protocol:
|
|
20
|
-
path: string;
|
|
21
|
-
cid: CID;
|
|
17
|
+
interface ParsedUrlStringResultsBase extends ResolveResult {
|
|
18
|
+
protocol: 'ipfs' | 'ipns';
|
|
22
19
|
query: ParsedUrlQuery;
|
|
20
|
+
/**
|
|
21
|
+
* seconds as a number
|
|
22
|
+
*/
|
|
23
|
+
ttl?: number;
|
|
23
24
|
}
|
|
25
|
+
export type ParsedUrlStringResults = ParsedUrlStringResultsBase;
|
|
24
26
|
/**
|
|
25
27
|
* A function that parses ipfs:// and ipns:// URLs, returning an object with easily recognizable properties.
|
|
26
28
|
*
|
|
27
29
|
* After determining the protocol successfully, we process the cidOrPeerIdOrDnsLink:
|
|
28
30
|
* * If it's ipfs, it parses the CID or throws an Aggregate error
|
|
29
31
|
* * If it's ipns, it attempts to resolve the PeerId and then the DNSLink. If both fail, an Aggregate error is thrown.
|
|
32
|
+
*
|
|
33
|
+
* @todo we need to break out each step of this function (cid parsing, ipns resolving, dnslink resolving) into separate functions and then remove the eslint-disable comment
|
|
30
34
|
*/
|
|
31
35
|
export declare function parseUrlString({ urlString, ipns, logger }: ParseUrlStringInput, options?: ParseUrlStringOptions): Promise<ParsedUrlStringResults>;
|
|
36
|
+
export {};
|
|
32
37
|
//# sourceMappingURL=parse-url-string.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-url-string.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-url-string.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"parse-url-string.d.ts","sourceRoot":"","sources":["../../../src/utils/parse-url-string.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AACzD,OAAO,KAAK,EAAwB,IAAI,EAAqB,iBAAiB,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACvK,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAItD,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAA;IACjB,IAAI,EAAE,IAAI,CAAA;IACV,MAAM,EAAE,eAAe,CAAA;CACxB;AACD,MAAM,WAAW,qBAAsB,SAAQ,eAAe,CAAC,qBAAqB,GAAG,iBAAiB,GAAG,4BAA4B,CAAC,EAAE,YAAY;CAErJ;AAED,MAAM,WAAW,cAAe,SAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC;IACtE,MAAM,CAAC,EAAE,sBAAsB,CAAA;IAC/B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED,UAAU,0BAA2B,SAAQ,aAAa;IACxD,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,KAAK,EAAE,cAAc,CAAA;IAErB;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,MAAM,MAAM,sBAAsB,GAAG,0BAA0B,CAAA;AA4F/D;;;;;;;;GAQG;AAEH,wBAAsB,cAAc,CAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,mBAAmB,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAgHxJ"}
|
|
@@ -6,15 +6,52 @@ const URL_REGEX = /^(?<protocol>ip[fn]s):\/\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\/?(
|
|
|
6
6
|
const PATH_REGEX = /^\/(?<protocol>ip[fn]s)\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/;
|
|
7
7
|
const PATH_GATEWAY_REGEX = /^https?:\/\/(.*[^/])\/(?<protocol>ip[fn]s)\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/;
|
|
8
8
|
const SUBDOMAIN_GATEWAY_REGEX = /^https?:\/\/(?<cidOrPeerIdOrDnsLink>[^/?]+)\.(?<protocol>ip[fn]s)\.([^/?]+)\/?(?<path>[^?]*)\??(?<queryString>.*)$/;
|
|
9
|
+
function matchUrlGroupsGuard(groups) {
|
|
10
|
+
const protocol = groups?.protocol;
|
|
11
|
+
if (protocol == null)
|
|
12
|
+
return false;
|
|
13
|
+
const cidOrPeerIdOrDnsLink = groups?.cidOrPeerIdOrDnsLink;
|
|
14
|
+
if (cidOrPeerIdOrDnsLink == null)
|
|
15
|
+
return false;
|
|
16
|
+
const path = groups?.path;
|
|
17
|
+
const queryString = groups?.queryString;
|
|
18
|
+
return ['ipns', 'ipfs'].includes(protocol) &&
|
|
19
|
+
typeof cidOrPeerIdOrDnsLink === 'string' &&
|
|
20
|
+
(path == null || typeof path === 'string') &&
|
|
21
|
+
(queryString == null || typeof queryString === 'string');
|
|
22
|
+
}
|
|
9
23
|
function matchURLString(urlString) {
|
|
10
24
|
for (const pattern of [URL_REGEX, PATH_REGEX, PATH_GATEWAY_REGEX, SUBDOMAIN_GATEWAY_REGEX]) {
|
|
11
25
|
const match = urlString.match(pattern);
|
|
12
|
-
if (match?.groups
|
|
26
|
+
if (matchUrlGroupsGuard(match?.groups)) {
|
|
13
27
|
return match.groups;
|
|
14
28
|
}
|
|
15
29
|
}
|
|
16
30
|
throw new TypeError(`Invalid URL: ${urlString}, please use ipfs://, ipns://, or gateway URLs only`);
|
|
17
31
|
}
|
|
32
|
+
/**
|
|
33
|
+
* determines the TTL for the resolved resource that will be used for the `Cache-Control` header's `max-age` directive.
|
|
34
|
+
* max-age is in seconds
|
|
35
|
+
*
|
|
36
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#response_directives
|
|
37
|
+
*
|
|
38
|
+
* If we have ipnsTtlNs, it will be a BigInt representing "nanoseconds". We need to convert it back to seconds.
|
|
39
|
+
*
|
|
40
|
+
* For more TTL nuances:
|
|
41
|
+
*
|
|
42
|
+
* @see https://github.com/ipfs/js-ipns/blob/16e0e10682fa9a663e0bb493a44d3e99a5200944/src/index.ts#L200
|
|
43
|
+
* @see https://github.com/ipfs/js-ipns/pull/308
|
|
44
|
+
*/
|
|
45
|
+
function calculateTtl(resolveResult) {
|
|
46
|
+
if (resolveResult == null) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
const dnsLinkTtl = resolveResult.answer?.TTL;
|
|
50
|
+
const ipnsTtlNs = resolveResult.record?.ttl;
|
|
51
|
+
// For some reason, ipns "nanoseconds" are 1e-8 of a second, instead of 1e-9.
|
|
52
|
+
const ipnsTtl = ipnsTtlNs != null ? Number(ipnsTtlNs / BigInt(1e8)) : undefined;
|
|
53
|
+
return dnsLinkTtl ?? ipnsTtl;
|
|
54
|
+
}
|
|
18
55
|
/**
|
|
19
56
|
* For dnslinks see https://specs.ipfs.tech/http-gateways/subdomain-gateway/#host-request-header
|
|
20
57
|
* DNSLink names include . which means they must be inlined into a single DNS label to provide unique origin and work with wildcard TLS certificates.
|
|
@@ -45,16 +82,23 @@ function dnsLinkLabelDecoder(linkLabel) {
|
|
|
45
82
|
* After determining the protocol successfully, we process the cidOrPeerIdOrDnsLink:
|
|
46
83
|
* * If it's ipfs, it parses the CID or throws an Aggregate error
|
|
47
84
|
* * If it's ipns, it attempts to resolve the PeerId and then the DNSLink. If both fail, an Aggregate error is thrown.
|
|
85
|
+
*
|
|
86
|
+
* @todo we need to break out each step of this function (cid parsing, ipns resolving, dnslink resolving) into separate functions and then remove the eslint-disable comment
|
|
48
87
|
*/
|
|
88
|
+
// eslint-disable-next-line complexity
|
|
49
89
|
export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
50
90
|
const log = logger.forComponent('helia:verified-fetch:parse-url-string');
|
|
51
91
|
const { protocol, cidOrPeerIdOrDnsLink, path: urlPath, queryString } = matchURLString(urlString);
|
|
52
92
|
let cid;
|
|
53
93
|
let resolvedPath;
|
|
54
94
|
const errors = [];
|
|
95
|
+
let resolveResult;
|
|
55
96
|
if (protocol === 'ipfs') {
|
|
56
97
|
try {
|
|
57
98
|
cid = CID.parse(cidOrPeerIdOrDnsLink);
|
|
99
|
+
/**
|
|
100
|
+
* no ttl set. @link {setCacheControlHeader}
|
|
101
|
+
*/
|
|
58
102
|
}
|
|
59
103
|
catch (err) {
|
|
60
104
|
log.error(err);
|
|
@@ -62,25 +106,26 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
62
106
|
}
|
|
63
107
|
}
|
|
64
108
|
else {
|
|
65
|
-
|
|
109
|
+
// protocol is ipns
|
|
110
|
+
resolveResult = ipnsCache.get(cidOrPeerIdOrDnsLink);
|
|
66
111
|
if (resolveResult != null) {
|
|
67
112
|
cid = resolveResult.cid;
|
|
68
113
|
resolvedPath = resolveResult.path;
|
|
69
114
|
log.trace('resolved %s to %c from cache', cidOrPeerIdOrDnsLink, cid);
|
|
70
115
|
}
|
|
71
116
|
else {
|
|
72
|
-
|
|
73
|
-
log.trace('attempting to resolve PeerId for %s', cidOrPeerIdOrDnsLink);
|
|
117
|
+
log.trace('Attempting to resolve PeerId for %s', cidOrPeerIdOrDnsLink);
|
|
74
118
|
let peerId = null;
|
|
75
119
|
try {
|
|
120
|
+
// try resolving as an IPNS name
|
|
76
121
|
peerId = peerIdFromString(cidOrPeerIdOrDnsLink);
|
|
77
|
-
resolveResult = await ipns.resolve(peerId,
|
|
122
|
+
resolveResult = await ipns.resolve(peerId, options);
|
|
78
123
|
cid = resolveResult?.cid;
|
|
79
124
|
resolvedPath = resolveResult?.path;
|
|
80
125
|
log.trace('resolved %s to %c', cidOrPeerIdOrDnsLink, cid);
|
|
81
|
-
ipnsCache.set(cidOrPeerIdOrDnsLink, resolveResult, 60 * 1000 * 2);
|
|
82
126
|
}
|
|
83
127
|
catch (err) {
|
|
128
|
+
options?.signal?.throwIfAborted();
|
|
84
129
|
if (peerId == null) {
|
|
85
130
|
log.error('could not parse PeerId string "%s"', cidOrPeerIdOrDnsLink, err);
|
|
86
131
|
errors.push(new TypeError(`Could not parse PeerId in ipns url "${cidOrPeerIdOrDnsLink}", ${err.message}`));
|
|
@@ -91,6 +136,7 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
91
136
|
}
|
|
92
137
|
}
|
|
93
138
|
if (cid == null) {
|
|
139
|
+
// cid is still null, try resolving as a DNSLink
|
|
94
140
|
let decodedDnsLinkLabel = cidOrPeerIdOrDnsLink;
|
|
95
141
|
if (isInlinedDnsLink(cidOrPeerIdOrDnsLink)) {
|
|
96
142
|
decodedDnsLinkLabel = dnsLinkLabelDecoder(cidOrPeerIdOrDnsLink);
|
|
@@ -98,13 +144,13 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
98
144
|
}
|
|
99
145
|
log.trace('Attempting to resolve DNSLink for %s', decodedDnsLinkLabel);
|
|
100
146
|
try {
|
|
101
|
-
resolveResult = await ipns.resolveDNSLink(decodedDnsLinkLabel,
|
|
147
|
+
resolveResult = await ipns.resolveDNSLink(decodedDnsLinkLabel, options);
|
|
102
148
|
cid = resolveResult?.cid;
|
|
103
149
|
resolvedPath = resolveResult?.path;
|
|
104
150
|
log.trace('resolved %s to %c', decodedDnsLinkLabel, cid);
|
|
105
|
-
ipnsCache.set(cidOrPeerIdOrDnsLink, resolveResult, 60 * 1000 * 2);
|
|
106
151
|
}
|
|
107
152
|
catch (err) {
|
|
153
|
+
options?.signal?.throwIfAborted();
|
|
108
154
|
log.error('could not resolve DnsLink for "%s"', cidOrPeerIdOrDnsLink, err);
|
|
109
155
|
errors.push(err);
|
|
110
156
|
}
|
|
@@ -117,6 +163,11 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
117
163
|
}
|
|
118
164
|
throw new AggregateError(errors, `Invalid resource. Cannot determine CID from URL "${urlString}"`);
|
|
119
165
|
}
|
|
166
|
+
const ttl = calculateTtl(resolveResult);
|
|
167
|
+
if (resolveResult != null) {
|
|
168
|
+
// use the ttl for the resolved resouce for the cache, but fallback to 2 minutes if not available
|
|
169
|
+
ipnsCache.set(cidOrPeerIdOrDnsLink, resolveResult, ttl ?? 60 * 1000 * 2);
|
|
170
|
+
}
|
|
120
171
|
// parse query string
|
|
121
172
|
const query = {};
|
|
122
173
|
if (queryString != null && queryString.length > 0) {
|
|
@@ -135,8 +186,9 @@ export async function parseUrlString({ urlString, ipns, logger }, options) {
|
|
|
135
186
|
return {
|
|
136
187
|
protocol,
|
|
137
188
|
cid,
|
|
138
|
-
path: joinPaths(resolvedPath, urlPath),
|
|
139
|
-
query
|
|
189
|
+
path: joinPaths(resolvedPath, urlPath ?? ''),
|
|
190
|
+
query,
|
|
191
|
+
ttl
|
|
140
192
|
};
|
|
141
193
|
}
|
|
142
194
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-url-string.js","sourceRoot":"","sources":["../../../src/utils/parse-url-string.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAMhC,MAAM,SAAS,GAAG,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"parse-url-string.js","sourceRoot":"","sources":["../../../src/utils/parse-url-string.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
interface CacheControlHeaderOptions {
|
|
2
|
+
/**
|
|
3
|
+
* This should be seconds as a number.
|
|
4
|
+
*
|
|
5
|
+
* See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#response_directives
|
|
6
|
+
*/
|
|
7
|
+
ttl?: number;
|
|
8
|
+
protocol: 'ipfs' | 'ipns';
|
|
9
|
+
response: Response;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Implementations may place an upper bound on any TTL received, as noted in Section 8 of [rfc2181].
|
|
13
|
+
* If TTL value is unknown, implementations should not send a Cache-Control
|
|
14
|
+
* No matter if TTL value is known or not, implementations should always send a Last-Modified header with the timestamp of the record resolution.
|
|
15
|
+
*
|
|
16
|
+
* @see https://specs.ipfs.tech/http-gateways/path-gateway/#cache-control-response-header
|
|
17
|
+
*/
|
|
18
|
+
export declare function setCacheControlHeader({ ttl, protocol, response }: CacheControlHeaderOptions): void;
|
|
1
19
|
/**
|
|
2
20
|
* This function returns the value of the `Content-Range` header for a given range.
|
|
3
21
|
* If you know the total size of the body, pass it as `byteSize`
|
|
@@ -9,4 +27,5 @@ export declare function getContentRangeHeader({ byteStart, byteEnd, byteSize }:
|
|
|
9
27
|
byteEnd: number | undefined;
|
|
10
28
|
byteSize: number | undefined;
|
|
11
29
|
}): string;
|
|
30
|
+
export {};
|
|
12
31
|
//# sourceMappingURL=response-headers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-headers.d.ts","sourceRoot":"","sources":["../../../src/utils/response-headers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,MAAM,CAmC7K"}
|
|
1
|
+
{"version":3,"file":"response-headers.d.ts","sourceRoot":"","sources":["../../../src/utils/response-headers.ts"],"names":[],"mappings":"AAAA,UAAU,yBAAyB;IACjC;;;;OAIG;IACH,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAA;IACzB,QAAQ,EAAE,QAAQ,CAAA;CACnB;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,yBAAyB,GAAG,IAAI,CAgBnG;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE;IAAE,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,MAAM,CAmC7K"}
|
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Implementations may place an upper bound on any TTL received, as noted in Section 8 of [rfc2181].
|
|
3
|
+
* If TTL value is unknown, implementations should not send a Cache-Control
|
|
4
|
+
* No matter if TTL value is known or not, implementations should always send a Last-Modified header with the timestamp of the record resolution.
|
|
5
|
+
*
|
|
6
|
+
* @see https://specs.ipfs.tech/http-gateways/path-gateway/#cache-control-response-header
|
|
7
|
+
*/
|
|
8
|
+
export function setCacheControlHeader({ ttl, protocol, response }) {
|
|
9
|
+
let headerValue;
|
|
10
|
+
if (protocol === 'ipfs') {
|
|
11
|
+
headerValue = 'public, max-age=29030400, immutable';
|
|
12
|
+
}
|
|
13
|
+
else if (ttl == null) {
|
|
14
|
+
/**
|
|
15
|
+
* default limit for unknown TTL: "use 5 minute as default fallback when it is not available."
|
|
16
|
+
*
|
|
17
|
+
* @see https://github.com/ipfs/boxo/issues/329#issuecomment-1995236409
|
|
18
|
+
*/
|
|
19
|
+
headerValue = 'public, max-age=300';
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
headerValue = `public, max-age=${ttl}`;
|
|
23
|
+
}
|
|
24
|
+
response.headers.set('cache-control', headerValue);
|
|
25
|
+
}
|
|
1
26
|
/**
|
|
2
27
|
* This function returns the value of the `Content-Range` header for a given range.
|
|
3
28
|
* If you know the total size of the body, pass it as `byteSize`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-headers.js","sourceRoot":"","sources":["../../../src/utils/response-headers.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"response-headers.js","sourceRoot":"","sources":["../../../src/utils/response-headers.ts"],"names":[],"mappings":"AAWA;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,EAA6B;IAC3F,IAAI,WAAmB,CAAA;IACvB,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,WAAW,GAAG,qCAAqC,CAAA;IACrD,CAAC;SAAM,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB;;;;WAIG;QACH,WAAW,GAAG,qBAAqB,CAAA;IACrC,CAAC;SAAM,CAAC;QACN,WAAW,GAAG,mBAAmB,GAAG,EAAE,CAAA;IACxC,CAAC;IAED,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,WAAW,CAAC,CAAA;AACpD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAE,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAgG;IACnK,MAAM,KAAK,GAAG,QAAQ,IAAI,GAAG,CAAA,CAAC,mDAAmD;IAEjF,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAA;IACrG,CAAC;IACD,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAA;IACvG,CAAC;IAED,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACzC,0BAA0B;QAC1B,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,WAAW,KAAK,EAAE,CAAA;QAC3B,CAAC;QACD,OAAO,SAAS,SAAS,IAAI,QAAQ,GAAG,CAAC,IAAI,QAAQ,EAAE,CAAA;IACzD,CAAC;IAED,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACzC,wBAAwB;QACxB,IAAI,QAAQ,IAAI,IAAI,EAAE,CAAC;YACrB,OAAO,WAAW,KAAK,EAAE,CAAA;QAC3B,CAAC;QACD,MAAM,GAAG,GAAG,QAAQ,GAAG,CAAC,CAAA;QACxB,MAAM,KAAK,GAAG,GAAG,GAAG,OAAO,GAAG,CAAC,CAAA;QAE/B,OAAO,SAAS,KAAK,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAA;IAC5C,CAAC;IAED,IAAI,SAAS,IAAI,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;QACzC,uDAAuD;QACvD,OAAO,WAAW,KAAK,EAAE,CAAA;IAC3B,CAAC;IAED,OAAO,SAAS,SAAS,IAAI,OAAO,IAAI,KAAK,EAAE,CAAA;AACjD,CAAC"}
|
|
@@ -8,7 +8,10 @@ export declare function okResponse(url: string, body?: SupportedBodyTypes, init?
|
|
|
8
8
|
export declare function badGatewayResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
9
9
|
export declare function notSupportedResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
10
10
|
export declare function notAcceptableResponse(url: string, body?: SupportedBodyTypes, init?: ResponseInit): Response;
|
|
11
|
-
|
|
11
|
+
/**
|
|
12
|
+
* if body is an Error, it will be converted to a string containing the error message.
|
|
13
|
+
*/
|
|
14
|
+
export declare function badRequestResponse(url: string, body?: SupportedBodyTypes | Error, init?: ResponseInit): Response;
|
|
12
15
|
export declare function movedPermanentlyResponse(url: string, location: string, init?: ResponseInit): Response;
|
|
13
16
|
interface RangeOptions {
|
|
14
17
|
byteRangeContext: ByteRangeContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/utils/responses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAuB/C,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,UAAU,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,QAAQ,CAgBpG;AAED,wBAAgB,kBAAkB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAWzG;AAED,wBAAgB,oBAAoB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAY3G;AAED,wBAAgB,qBAAqB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAW5G;AAED,wBAAgB,kBAAkB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,
|
|
1
|
+
{"version":3,"file":"responses.d.ts","sourceRoot":"","sources":["../../../src/utils/responses.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAuB/C,MAAM,WAAW,eAAgB,SAAQ,YAAY;IACnD,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,wBAAgB,UAAU,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,QAAQ,CAgBpG;AAED,wBAAgB,kBAAkB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAWzG;AAED,wBAAgB,oBAAoB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAY3G;AAED,wBAAgB,qBAAqB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAW5G;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,GAAG,KAAK,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAcjH;AAED,wBAAgB,wBAAwB,CAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAetG;AAED,UAAU,YAAY;IACpB,gBAAgB,EAAE,gBAAgB,CAAA;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED,wBAAgB,eAAe,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,EAAE,EAAE,gBAAgB,EAAE,GAAG,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,EAAE,eAAe,GAAG,QAAQ,CAkCjJ;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,kBAAkB,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,QAAQ,CAWvG"}
|
|
@@ -60,7 +60,13 @@ export function notAcceptableResponse(url, body, init) {
|
|
|
60
60
|
setUrl(response, url);
|
|
61
61
|
return response;
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* if body is an Error, it will be converted to a string containing the error message.
|
|
65
|
+
*/
|
|
63
66
|
export function badRequestResponse(url, body, init) {
|
|
67
|
+
if (body instanceof Error) {
|
|
68
|
+
body = body.message;
|
|
69
|
+
}
|
|
64
70
|
const response = new Response(body, {
|
|
65
71
|
...(init ?? {}),
|
|
66
72
|
status: 400,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"responses.js","sourceRoot":"","sources":["../../../src/utils/responses.ts"],"names":[],"mappings":"AAIA,SAAS,QAAQ,CAAE,QAAkB,EAAE,IAAY,EAAE,KAAuB;IAC1E,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE,IAAI,EAAE;QACpC,UAAU,EAAE,IAAI;QAChB,YAAY,EAAE,KAAK;QACnB,GAAG,EAAE,GAAG,EAAE,GAAE,CAAC;QACb,GAAG,EAAE,GAAG,EAAE,CAAC,KAAK;KACjB,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,OAAO,CAAE,QAAkB,EAAE,KAA+D;IACnG,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,CAAC,CAAA;AACnC,CAAC;AAED,SAAS,MAAM,CAAE,QAAkB,EAAE,KAAa;IAChD,QAAQ,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;AAClC,CAAC;AAED,SAAS,aAAa,CAAE,QAAkB;IACxC,QAAQ,CAAC,QAAQ,EAAE,YAAY,EAAE,IAAI,CAAC,CAAA;AACxC,CAAC;AAMD,MAAM,UAAU,UAAU,CAAE,GAAW,EAAE,IAAyB,EAAE,IAAsB;IACxF,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE;QAClC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QACf,MAAM,EAAE,GAAG;QACX,UAAU,EAAE,IAAI;KACjB,CAAC,CAAA;IAEF,IAAI,IAAI,EAAE,UAAU,KAAK,IAAI,EAAE,CAAC;QAC9B,aAAa,CAAC,QAAQ,CAAC,CAAA;IACzB,CAAC;IAED,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC1B,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IACrB,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,OAAO,CAAC,CAAA;IAE9C,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAE,GAAW,EAAE,IAAyB,EAAE,IAAmB;IAC7F,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE;QAClC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QACf,MAAM,EAAE,GAAG;QACX,UAAU,EAAE,aAAa;KAC1B,CAAC,CAAA;IAEF,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC1B,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAErB,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAE,GAAW,EAAE,IAAyB,EAAE,IAAmB;IAC/F,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE;QAClC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QACf,MAAM,EAAE,GAAG;QACX,UAAU,EAAE,iBAAiB;KAC9B,CAAC,CAAA;IACF,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,EAAE,SAAS,CAAC,CAAA,CAAC,iGAAiG;IAE3J,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC1B,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAErB,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAE,GAAW,EAAE,IAAyB,EAAE,IAAmB;IAChG,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE;QAClC,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC;QACf,MAAM,EAAE,GAAG;QACX,UAAU,EAAE,gBAAgB;KAC7B,CAAC,CAAA;IAEF,OAAO,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAA;IAC1B,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;IAErB,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAE,GAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"responses.js","sourceRoot":"","sources":["../../../src/utils/responses.ts"],"names":[],"mappings":"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"}
|
|
@@ -47,6 +47,18 @@ export declare class VerifiedFetch {
|
|
|
47
47
|
* use the CID codec to choose an appropriate handler for the block data.
|
|
48
48
|
*/
|
|
49
49
|
private readonly codecHandlers;
|
|
50
|
+
/**
|
|
51
|
+
*
|
|
52
|
+
* TODO: Should we use 400, 408, 418, or 425, or throw and not even return a response?
|
|
53
|
+
*/
|
|
54
|
+
private abortHandler;
|
|
55
|
+
/**
|
|
56
|
+
* We're starting to get to the point where we need a queue or pipeline of
|
|
57
|
+
* operations to perform and a single place to handle errors.
|
|
58
|
+
*
|
|
59
|
+
* TODO: move operations called by fetch to a queue of operations where we can
|
|
60
|
+
* always exit early (and cleanly) if a given signal is aborted
|
|
61
|
+
*/
|
|
50
62
|
fetch(resource: Resource, opts?: VerifiedFetchOptions): Promise<Response>;
|
|
51
63
|
/**
|
|
52
64
|
* Start the Helia instance
|
|
@@ -1 +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;AAC1D,OAAO,EAAyB,KAAK,MAAM,IAAI,WAAW,EAAE,MAAM,eAAe,CAAA;
|
|
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;AAC1D,OAAO,EAAyB,KAAK,MAAM,IAAI,WAAW,EAAE,MAAM,eAAe,CAAA;AA0BjF,OAAO,KAAK,EAAa,iBAAiB,EAAE,QAAQ,EAAE,iBAAiB,IAAI,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAGnH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAI9D,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;IACrC,YAAY,CAAC,EAAE,WAAW,EAAE,CAAA;CAC7B;AA2ED,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;IASvF;;;OAGG;YACW,gBAAgB;IAgC9B;;;OAGG;YACW,SAAS;IAUvB;;;OAGG;YACW,SAAS;YAaT,UAAU;YA0BV,aAAa;YA8Cb,WAAW;YAqGX,SAAS;YAqBT,cAAc;IA0B5B;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,aAAa,CAO7B;IAED;;;OAGG;YACW,YAAY;IAK1B;;;;;;OAMG;IACG,KAAK,CAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,EAAE,oBAAoB,GAAG,OAAO,CAAC,QAAQ,CAAC;IA+HhF;;OAEG;IACG,KAAK,IAAK,OAAO,CAAC,IAAI,CAAC;IAI7B;;OAEG;IACG,IAAI,IAAK,OAAO,CAAC,IAAI,CAAC;CAG7B"}
|
|
@@ -22,6 +22,7 @@ import { getETag } from './utils/get-e-tag.js';
|
|
|
22
22
|
import { getStreamFromAsyncIterable } from './utils/get-stream-from-async-iterable.js';
|
|
23
23
|
import { tarStream } from './utils/get-tar-stream.js';
|
|
24
24
|
import { parseResource } from './utils/parse-resource.js';
|
|
25
|
+
import { setCacheControlHeader } from './utils/response-headers.js';
|
|
25
26
|
import { badRequestResponse, movedPermanentlyResponse, notAcceptableResponse, notSupportedResponse, okResponse, badRangeResponse, okRangeResponse, badGatewayResponse } from './utils/responses.js';
|
|
26
27
|
import { selectOutputType, queryFormatToAcceptHeader } from './utils/select-output-type.js';
|
|
27
28
|
import { walkPath } from './utils/walk-path.js';
|
|
@@ -33,6 +34,9 @@ function convertOptions(options) {
|
|
|
33
34
|
if (options?.signal === null) {
|
|
34
35
|
signal = undefined;
|
|
35
36
|
}
|
|
37
|
+
else {
|
|
38
|
+
signal = options?.signal;
|
|
39
|
+
}
|
|
36
40
|
return {
|
|
37
41
|
...options,
|
|
38
42
|
signal
|
|
@@ -213,7 +217,10 @@ export class VerifiedFetch {
|
|
|
213
217
|
}
|
|
214
218
|
catch (err) {
|
|
215
219
|
this.log.error('error walking path %s', path, err);
|
|
216
|
-
|
|
220
|
+
if (options?.signal?.aborted === true) {
|
|
221
|
+
return badRequestResponse(resource.toString(), new Error('signal aborted by user'));
|
|
222
|
+
}
|
|
223
|
+
return badGatewayResponse(resource.toString(), 'Error walking path');
|
|
217
224
|
}
|
|
218
225
|
let resolvedCID = terminalElement?.cid ?? cid;
|
|
219
226
|
if (terminalElement?.type === 'directory') {
|
|
@@ -269,7 +276,8 @@ export class VerifiedFetch {
|
|
|
269
276
|
this.log('got async iterator for %c/%s', cid, path);
|
|
270
277
|
try {
|
|
271
278
|
const { stream, firstChunk } = await getStreamFromAsyncIterable(asyncIter, path ?? '', this.helia.logger, {
|
|
272
|
-
onProgress: options?.onProgress
|
|
279
|
+
onProgress: options?.onProgress,
|
|
280
|
+
signal: options?.signal
|
|
273
281
|
});
|
|
274
282
|
byteRangeContext.setBody(stream);
|
|
275
283
|
// if not a valid range request, okRangeRequest will call okResponse
|
|
@@ -287,7 +295,7 @@ export class VerifiedFetch {
|
|
|
287
295
|
if (byteRangeContext.isRangeRequest && err.code === 'ERR_INVALID_PARAMS') {
|
|
288
296
|
return badRangeResponse(resource);
|
|
289
297
|
}
|
|
290
|
-
return badGatewayResponse('Unable to stream content');
|
|
298
|
+
return badGatewayResponse(resource.toString(), 'Unable to stream content');
|
|
291
299
|
}
|
|
292
300
|
}
|
|
293
301
|
async handleRaw({ resource, cid, path, options }) {
|
|
@@ -345,23 +353,47 @@ export class VerifiedFetch {
|
|
|
345
353
|
[rawCode]: this.handleRaw,
|
|
346
354
|
[identity.code]: this.handleRaw
|
|
347
355
|
};
|
|
356
|
+
/**
|
|
357
|
+
*
|
|
358
|
+
* TODO: Should we use 400, 408, 418, or 425, or throw and not even return a response?
|
|
359
|
+
*/
|
|
360
|
+
async abortHandler(opController) {
|
|
361
|
+
this.log.error('signal aborted by user');
|
|
362
|
+
opController.abort('signal aborted by user');
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* We're starting to get to the point where we need a queue or pipeline of
|
|
366
|
+
* operations to perform and a single place to handle errors.
|
|
367
|
+
*
|
|
368
|
+
* TODO: move operations called by fetch to a queue of operations where we can
|
|
369
|
+
* always exit early (and cleanly) if a given signal is aborted
|
|
370
|
+
*/
|
|
348
371
|
async fetch(resource, opts) {
|
|
349
372
|
this.log('fetch %s', resource);
|
|
350
373
|
const options = convertOptions(opts);
|
|
374
|
+
const opController = new AbortController();
|
|
375
|
+
if (options?.signal != null) {
|
|
376
|
+
options.signal.onabort = this.abortHandler.bind(this, opController);
|
|
377
|
+
options.signal = opController.signal;
|
|
378
|
+
}
|
|
351
379
|
options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:start', { resource }));
|
|
352
380
|
// resolve the CID/path from the requested resource
|
|
353
381
|
let cid;
|
|
354
382
|
let path;
|
|
355
383
|
let query;
|
|
384
|
+
let ttl;
|
|
385
|
+
let protocol;
|
|
356
386
|
try {
|
|
357
387
|
const result = await parseResource(resource, { ipns: this.ipns, logger: this.helia.logger }, options);
|
|
358
388
|
cid = result.cid;
|
|
359
389
|
path = result.path;
|
|
360
390
|
query = result.query;
|
|
391
|
+
ttl = result.ttl;
|
|
392
|
+
protocol = result.protocol;
|
|
361
393
|
}
|
|
362
394
|
catch (err) {
|
|
363
395
|
this.log.error('error parsing resource %s', resource, err);
|
|
364
|
-
return badRequestResponse(
|
|
396
|
+
return badRequestResponse(resource.toString(), err);
|
|
365
397
|
}
|
|
366
398
|
options?.onProgress?.(new CustomProgressEvent('verified-fetch:request:resolve', { cid, path }));
|
|
367
399
|
const requestHeaders = new Headers(options?.headers);
|
|
@@ -419,7 +451,7 @@ export class VerifiedFetch {
|
|
|
419
451
|
response = await codecHandler.call(this, handlerArgs);
|
|
420
452
|
}
|
|
421
453
|
response.headers.set('etag', getETag({ cid, reqFormat, weak: false }));
|
|
422
|
-
|
|
454
|
+
setCacheControlHeader({ response, ttl, protocol });
|
|
423
455
|
// https://specs.ipfs.tech/http-gateways/path-gateway/#x-ipfs-path-response-header
|
|
424
456
|
response.headers.set('X-Ipfs-Path', resource.toString());
|
|
425
457
|
// set Content-Disposition header
|