@helia/trustless-gateway-client 0.0.0-1361bfa5

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trustless-gateway.js","sourceRoot":"","sources":["../../src/trustless-gateway.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { TrustlessGateway } from './trustless-gateway.ts';
2
+ import type { TrustlessGatewayGetBlockProgressEvents } from './index.ts';
3
+ import type { TransformRequestInit } from './trustless-gateway.ts';
4
+ import type { Routing } from '@helia/interface';
5
+ import type { Multiaddr } from '@multiformats/multiaddr';
6
+ import type { AbortOptions } from 'abort-error';
7
+ import type { ComponentLogger, Logger } from 'birnam';
8
+ import type { CID } from 'multiformats/cid';
9
+ import type { ProgressOptions } from 'progress-events';
10
+ export declare function filterNonHTTPMultiaddrs(multiaddrs: Multiaddr[], allowInsecure: boolean, allowLocal: boolean): Multiaddr[];
11
+ export interface FindHttpGatewayProvidersOptions extends AbortOptions, ProgressOptions<TrustlessGatewayGetBlockProgressEvents> {
12
+ transformRequestInit?: TransformRequestInit;
13
+ }
14
+ export declare function findHttpGatewayProviders(cid: CID, routing: Routing, logger: ComponentLogger, allowInsecure: boolean, allowLocal: boolean, options?: FindHttpGatewayProvidersOptions): AsyncGenerator<TrustlessGateway>;
15
+ interface LimitedResponseOptions {
16
+ signal?: AbortSignal;
17
+ log?: Logger;
18
+ }
19
+ /**
20
+ * A function that handles ensuring the content-length header and the response body is less than a given byte limit.
21
+ *
22
+ * If the response contains a content-length header greater than the limit or the actual bytes returned are greater than
23
+ * the limit, an error is thrown.
24
+ */
25
+ export declare function limitedResponse(response: Response, byteLimit: number, options?: LimitedResponseOptions): Promise<Uint8Array>;
26
+ export {};
27
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAA;AACzD,OAAO,KAAK,EAAE,sCAAsC,EAAE,MAAM,YAAY,CAAA;AACxE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAClE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,kBAAkB,CAAA;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAA;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC/C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACrD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,wBAAgB,uBAAuB,CAAE,UAAU,EAAE,SAAS,EAAE,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,GAAG,SAAS,EAAE,CAiC1H;AAED,MAAM,WAAW,+BAAgC,SAAQ,YAAY,EAAE,eAAe,CAAC,sCAAsC,CAAC;IAC5H,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;CAC5C;AAED,wBAAwB,wBAAwB,CAAE,GAAG,EAAE,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,eAAe,EAAE,aAAa,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,GAAE,+BAAoC,GAAG,cAAc,CAAC,gBAAgB,CAAC,CAqBnO;AAED,UAAU,sBAAsB;IAC9B,MAAM,CAAC,EAAE,WAAW,CAAA;IACpB,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,UAAU,CAAC,CAqDnI"}
@@ -0,0 +1,106 @@
1
+ import { getNetConfig, isPrivate } from '@libp2p/utils';
2
+ import { DNS, HTTP, HTTPS } from '@multiformats/multiaddr-matcher';
3
+ import { multiaddrToUri } from '@multiformats/multiaddr-to-uri';
4
+ import { Uint8ArrayList } from 'uint8arraylist';
5
+ import { TrustlessGateway } from "./trustless-gateway.js";
6
+ export function filterNonHTTPMultiaddrs(multiaddrs, allowInsecure, allowLocal) {
7
+ return multiaddrs.filter(ma => {
8
+ const isHttps = HTTPS.exactMatch(ma);
9
+ const isHttp = HTTP.exactMatch(ma);
10
+ if (!isHttps && !isHttp) {
11
+ return false;
12
+ }
13
+ if (isHttps || (allowInsecure && isHttp)) {
14
+ if (allowLocal) {
15
+ return true;
16
+ }
17
+ if (DNS.matches(ma)) {
18
+ return true;
19
+ }
20
+ return isPrivate(ma) === false;
21
+ }
22
+ // When allowInsecure is false and allowLocal is true, allow multiaddrs with
23
+ // "127.0.0.1", "localhost", or any subdomain ending with ".localhost"
24
+ if (!allowInsecure && allowLocal) {
25
+ const { host } = getNetConfig(ma);
26
+ if (host === '127.0.0.1' || host === 'localhost' || host.endsWith('.localhost')) {
27
+ return true;
28
+ }
29
+ }
30
+ return false;
31
+ });
32
+ }
33
+ export async function* findHttpGatewayProviders(cid, routing, logger, allowInsecure, allowLocal, options = {}) {
34
+ for await (const provider of routing.findProviders(cid, options)) {
35
+ // require http(s) addresses
36
+ const httpAddresses = filterNonHTTPMultiaddrs(provider.multiaddrs, allowInsecure, allowLocal);
37
+ if (httpAddresses.length === 0) {
38
+ continue;
39
+ }
40
+ // take first address?
41
+ // /ip4/x.x.x.x/tcp/31337/http
42
+ // /ip4/x.x.x.x/tcp/31337/https
43
+ // etc
44
+ const uri = new URL(multiaddrToUri(httpAddresses[0]));
45
+ yield new TrustlessGateway(uri, {
46
+ logger,
47
+ transformRequestInit: options.transformRequestInit,
48
+ routing: provider.routing
49
+ });
50
+ }
51
+ }
52
+ /**
53
+ * A function that handles ensuring the content-length header and the response body is less than a given byte limit.
54
+ *
55
+ * If the response contains a content-length header greater than the limit or the actual bytes returned are greater than
56
+ * the limit, an error is thrown.
57
+ */
58
+ export async function limitedResponse(response, byteLimit, options) {
59
+ const { signal, log } = options ?? {};
60
+ const contentLength = response.headers.get('content-length');
61
+ if (contentLength != null) {
62
+ const contentLengthNumber = parseInt(contentLength, 10);
63
+ if (contentLengthNumber > byteLimit) {
64
+ log?.error('content-length header (%d) is greater than the limit (%d)', contentLengthNumber, byteLimit);
65
+ if (response.body != null) {
66
+ await response.body.cancel().catch(err => {
67
+ log?.error('error cancelling response body after content-length check - %e', err);
68
+ });
69
+ }
70
+ throw new Error(`Content-Length header (${contentLengthNumber}) is greater than the limit (${byteLimit}).`);
71
+ }
72
+ }
73
+ const reader = response.body?.getReader();
74
+ if (reader == null) {
75
+ // no body to consume if reader is null
76
+ throw new Error('Response body is not readable');
77
+ }
78
+ const chunkList = new Uint8ArrayList();
79
+ try {
80
+ while (true) {
81
+ if (signal?.aborted === true) {
82
+ throw new Error('Response body read was aborted.');
83
+ }
84
+ const { done, value } = await reader.read();
85
+ if (done) {
86
+ break;
87
+ }
88
+ chunkList.append(value);
89
+ if (chunkList.byteLength > byteLimit) {
90
+ // No need to consume body here, as we were streaming and hit the limit
91
+ throw new Error(`Response body is greater than the limit (${byteLimit}), received ${chunkList.byteLength} bytes.`);
92
+ }
93
+ }
94
+ }
95
+ finally {
96
+ reader.cancel()
97
+ .catch(err => {
98
+ log?.error('error cancelling reader - %e', err);
99
+ })
100
+ .finally(() => {
101
+ reader.releaseLock();
102
+ });
103
+ }
104
+ return chunkList.subarray();
105
+ }
106
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@helia/trustless-gateway-client",
3
+ "version": "0.0.0-1361bfa5",
4
+ "description": "Use Trustless HTTP Gateways with Helia",
5
+ "license": "Apache-2.0 OR MIT",
6
+ "homepage": "https://github.com/ipfs/helia/tree/main/packages/trustless-gateway-client#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ipfs/helia.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/ipfs/helia/issues"
13
+ },
14
+ "publishConfig": {
15
+ "access": "public",
16
+ "provenance": true
17
+ },
18
+ "keywords": [
19
+ "IPFS"
20
+ ],
21
+ "type": "module",
22
+ "types": "./dist/src/index.d.ts",
23
+ "files": [
24
+ "src",
25
+ "dist",
26
+ "!dist/test",
27
+ "!**/*.tsbuildinfo"
28
+ ],
29
+ "exports": {
30
+ ".": {
31
+ "types": "./dist/src/index.d.ts",
32
+ "import": "./dist/src/index.js",
33
+ "module-sync": "./dist/src/index.js"
34
+ }
35
+ },
36
+ "scripts": {
37
+ "clean": "aegir clean",
38
+ "lint": "aegir lint",
39
+ "dep-check": "aegir dep-check",
40
+ "doc-check": "aegir doc-check",
41
+ "build": "aegir build",
42
+ "test": "aegir test",
43
+ "test:chrome": "aegir test -t browser --cov",
44
+ "test:chrome-webworker": "aegir test -t webworker",
45
+ "test:firefox": "aegir test -t browser -- --browser firefox",
46
+ "test:firefox-webworker": "aegir test -t webworker -- --browser firefox",
47
+ "test:node": "aegir test -t node --cov",
48
+ "test:electron-main": "aegir test -t electron-main"
49
+ },
50
+ "dependencies": {
51
+ "@helia/interface": "6.2.1-1361bfa5",
52
+ "@helia/utils": "2.5.2-1361bfa5",
53
+ "@libp2p/utils": "^7.2.2",
54
+ "@multiformats/multiaddr": "^13.0.3",
55
+ "@multiformats/multiaddr-matcher": "^3.0.2",
56
+ "@multiformats/multiaddr-to-uri": "^12.0.0",
57
+ "@multiformats/uri-to-multiaddr": "^10.0.0",
58
+ "abort-error": "^1.0.2",
59
+ "birnam": "^1.0.0",
60
+ "multiformats": "^14.0.0",
61
+ "progress-events": "^1.1.0",
62
+ "uint8arraylist": "^3.0.2",
63
+ "uint8arrays": "^6.1.1"
64
+ },
65
+ "devDependencies": {
66
+ "@ipshipyard/crypto": "^1.1.0",
67
+ "aegir": "^48.0.11",
68
+ "cors": "^2.8.6",
69
+ "polka": "^0.5.2",
70
+ "race-signal": "^2.0.0",
71
+ "sinon": "^22.0.0",
72
+ "sinon-ts": "^2.0.0"
73
+ },
74
+ "browser": {
75
+ "./dist/src/utils/delegated-http-routing-defaults.js": "./dist/src/utils/delegated-http-routing-defaults.browser.js"
76
+ },
77
+ "sideEffects": false
78
+ }
package/src/broker.ts ADDED
@@ -0,0 +1,112 @@
1
+ import { DEFAULT_ALLOW_INSECURE, DEFAULT_ALLOW_LOCAL } from './index.ts'
2
+ import { createTrustlessGatewaySession } from './session.ts'
3
+ import { findHttpGatewayProviders } from './utils.ts'
4
+ import type { TrustlessGatewayBlockBrokerInit, TrustlessGatewayBlockBrokerComponents, TrustlessGatewayGetBlockProgressEvents } from './index.ts'
5
+ import type { TransformRequestInit } from './trustless-gateway.ts'
6
+ import type { Routing, BlockRetrievalOptions, BlockBroker, CreateSessionOptions, SessionBlockBroker } from '@helia/interface'
7
+ import type { ComponentLogger, Logger } from 'birnam'
8
+ import type { CID } from 'multiformats/cid'
9
+
10
+ export interface CreateTrustlessGatewaySessionOptions extends CreateSessionOptions<TrustlessGatewayGetBlockProgressEvents> {
11
+ /**
12
+ * By default we will only connect to peers with HTTPS addresses, pass true
13
+ * to also connect to HTTP addresses.
14
+ *
15
+ * @default false
16
+ */
17
+ allowInsecure?: boolean
18
+
19
+ /**
20
+ * By default we will only connect to peers with public or DNS addresses, pass
21
+ * true to also connect to private addresses.
22
+ *
23
+ * @default false
24
+ */
25
+ allowLocal?: boolean
26
+
27
+ /**
28
+ * Provide a function that will be called before querying trustless-gateways.
29
+ *
30
+ * This lets you modify the fetch options to pass custom headers or other
31
+ * necessary things.
32
+ */
33
+ transformRequestInit?: TransformRequestInit
34
+ }
35
+
36
+ /**
37
+ * A class that accepts a list of trustless gateways that are queried
38
+ * for blocks.
39
+ */
40
+ export class TrustlessGatewayBlockBroker implements BlockBroker<TrustlessGatewayGetBlockProgressEvents> {
41
+ public readonly name = 'trustless-gateway'
42
+ private readonly allowInsecure: boolean
43
+ private readonly allowLocal: boolean
44
+ private readonly transformRequestInit?: TransformRequestInit
45
+ private readonly routing: Routing
46
+ private readonly log: Logger
47
+ private readonly logger: ComponentLogger
48
+
49
+ constructor (components: TrustlessGatewayBlockBrokerComponents, init: TrustlessGatewayBlockBrokerInit = {}) {
50
+ this.log = components.logger.forComponent('helia:trustless-gateway-block-broker')
51
+ this.logger = components.logger
52
+ this.routing = components.routing
53
+ this.allowInsecure = init.allowInsecure ?? DEFAULT_ALLOW_INSECURE
54
+ this.allowLocal = init.allowLocal ?? DEFAULT_ALLOW_LOCAL
55
+ this.transformRequestInit = init.transformRequestInit
56
+ }
57
+
58
+ async retrieve (cid: CID, options: BlockRetrievalOptions<TrustlessGatewayGetBlockProgressEvents> = {}): Promise<Uint8Array> {
59
+ const aggregateErrors: Error[] = []
60
+
61
+ for await (const gateway of findHttpGatewayProviders(cid, this.routing, this.logger, this.allowInsecure, this.allowLocal, { ...options, transformRequestInit: this.transformRequestInit })) {
62
+ this.log('getting block for %c from %s', cid, gateway.url)
63
+
64
+ try {
65
+ const block = await gateway.getRawBlock(cid, options)
66
+ this.log.trace('got block for %c from %s', cid, gateway.url)
67
+
68
+ try {
69
+ await options.validateFn?.(block)
70
+ } catch (err) {
71
+ this.log.error('failed to validate block for %c from %s - %e', cid, gateway.url, err)
72
+ // try another gateway
73
+ continue
74
+ }
75
+
76
+ return block
77
+ } catch (err: unknown) {
78
+ this.log.error('failed to get block for %c from %s - %e', cid, gateway.url, err)
79
+
80
+ if (err instanceof Error) {
81
+ aggregateErrors.push(err)
82
+ } else {
83
+ aggregateErrors.push(new Error(`Unable to fetch raw block for CID ${cid} from gateway ${gateway.url}`))
84
+ }
85
+
86
+ // if signal was aborted, exit the loop
87
+ if (options.signal?.aborted === true) {
88
+ this.log.trace('request aborted while fetching raw block for CID %c from gateway %s', cid, gateway.url)
89
+ break
90
+ }
91
+ }
92
+ }
93
+
94
+ if (aggregateErrors.length > 0) {
95
+ throw new AggregateError(aggregateErrors, `Unable to fetch raw block for CID ${cid} from any gateway`)
96
+ } else {
97
+ throw new Error(`Unable to fetch raw block for CID ${cid} from any gateway`)
98
+ }
99
+ }
100
+
101
+ createSession (options: CreateTrustlessGatewaySessionOptions = {}): SessionBlockBroker<TrustlessGatewayGetBlockProgressEvents> {
102
+ return createTrustlessGatewaySession({
103
+ logger: this.logger,
104
+ routing: this.routing
105
+ }, {
106
+ ...options,
107
+ allowLocal: this.allowLocal,
108
+ allowInsecure: this.allowInsecure,
109
+ transformRequestInit: this.transformRequestInit
110
+ })
111
+ }
112
+ }
package/src/index.ts ADDED
@@ -0,0 +1,81 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * A Trustless Gateway is an HTTP endpoint that can be used to download blocks
5
+ * or CAR files in a verifiable way.
6
+ */
7
+
8
+ import { TrustlessGatewayBlockBroker } from './broker.ts'
9
+ import type { TransformRequestInit } from './trustless-gateway.ts'
10
+ import type { Routing, BlockBroker, RoutingFindProvidersProgressEvents, BlockBrokerGetBlockProgressEvents } from '@helia/interface'
11
+ import type { ComponentLogger } from 'birnam'
12
+ import type { CID } from 'multiformats'
13
+ import type { ProgressEvent } from 'progress-events'
14
+
15
+ export const DEFAULT_ALLOW_INSECURE = false
16
+ export const DEFAULT_ALLOW_LOCAL = false
17
+ /**
18
+ * The maximum number of bytes to allow when fetching a raw block.
19
+ *
20
+ * @see https://specs.ipfs.tech/bitswap-protocol/#block-sizes
21
+ */
22
+ export const DEFAULT_MAX_SIZE = 2_097_152
23
+
24
+ export interface TrustlessGatewayProvider {
25
+ /**
26
+ * The type of provider
27
+ */
28
+ type: 'trustless-gateway'
29
+
30
+ /**
31
+ * The CID that the provider can provide the block for
32
+ */
33
+ cid: CID
34
+
35
+ /**
36
+ * The provider's URL
37
+ */
38
+ url: string
39
+
40
+ /**
41
+ * Which routing implementation found the provider
42
+ */
43
+ routing: string
44
+ }
45
+
46
+ export type TrustlessGatewayGetBlockProgressEvents =
47
+ ProgressEvent<'trustless-gateway:get-block:fetch', URL> |
48
+ ProgressEvent<'trustless-gateway:found-provider', TrustlessGatewayProvider> |
49
+ RoutingFindProvidersProgressEvents |
50
+ BlockBrokerGetBlockProgressEvents
51
+
52
+ export interface TrustlessGatewayBlockBrokerInit {
53
+ /**
54
+ * By default we will only connect to peers with HTTPS addresses, pass true
55
+ * to also connect to HTTP addresses.
56
+ *
57
+ * @default false
58
+ */
59
+ allowInsecure?: boolean
60
+
61
+ /**
62
+ * By default we will only connect to peers with public or DNS addresses, pass
63
+ * true to also connect to private addresses.
64
+ *
65
+ * @default false
66
+ */
67
+ allowLocal?: boolean
68
+ /**
69
+ * Provide a function that will be called before querying trustless-gateways. This lets you modify the fetch options to pass custom headers or other necessary things.
70
+ */
71
+ transformRequestInit?: TransformRequestInit
72
+ }
73
+
74
+ export interface TrustlessGatewayBlockBrokerComponents {
75
+ routing: Routing
76
+ logger: ComponentLogger
77
+ }
78
+
79
+ export function trustlessGatewayBlockBroker (init: TrustlessGatewayBlockBrokerInit = {}): (components: TrustlessGatewayBlockBrokerComponents) => BlockBroker<TrustlessGatewayGetBlockProgressEvents> {
80
+ return (components) => new TrustlessGatewayBlockBroker(components, init)
81
+ }
package/src/session.ts ADDED
@@ -0,0 +1,119 @@
1
+ import { AbstractSession, isCID } from '@helia/utils'
2
+ import { multiaddrToUri } from '@multiformats/multiaddr-to-uri'
3
+ import { CID } from 'multiformats/cid'
4
+ import { CustomProgressEvent } from 'progress-events'
5
+ import { DEFAULT_ALLOW_INSECURE, DEFAULT_ALLOW_LOCAL } from './index.ts'
6
+ import { TrustlessGateway } from './trustless-gateway.ts'
7
+ import { filterNonHTTPMultiaddrs, findHttpGatewayProviders } from './utils.ts'
8
+ import type { CreateTrustlessGatewaySessionOptions } from './broker.ts'
9
+ import type { TrustlessGatewayGetBlockProgressEvents, TrustlessGatewayProvider } from './index.ts'
10
+ import type { TransformRequestInit } from './trustless-gateway.ts'
11
+ import type { BlockRetrievalOptions, Routing } from '@helia/interface'
12
+ import type { Multiaddr } from '@multiformats/multiaddr'
13
+ import type { AbortOptions } from 'abort-error'
14
+ import type { ComponentLogger } from 'birnam'
15
+
16
+ export interface TrustlessGatewaySessionComponents {
17
+ logger: ComponentLogger
18
+ routing: Routing
19
+ }
20
+
21
+ class TrustlessGatewaySession extends AbstractSession<TrustlessGateway, TrustlessGatewayGetBlockProgressEvents> {
22
+ public readonly name = 'trustless-gateway-session'
23
+ private readonly routing: Routing
24
+ private readonly allowInsecure: boolean
25
+ private readonly allowLocal: boolean
26
+ private readonly transformRequestInit?: TransformRequestInit
27
+
28
+ constructor (components: TrustlessGatewaySessionComponents, init: CreateTrustlessGatewaySessionOptions) {
29
+ super(components, {
30
+ ...init,
31
+ name: 'helia:trustless-gateway:session'
32
+ })
33
+
34
+ this.routing = components.routing
35
+ this.allowInsecure = init.allowInsecure ?? DEFAULT_ALLOW_INSECURE
36
+ this.allowLocal = init.allowLocal ?? DEFAULT_ALLOW_LOCAL
37
+ this.transformRequestInit = init.transformRequestInit
38
+ }
39
+
40
+ async queryProvider (cid: CID, provider: TrustlessGateway, options: BlockRetrievalOptions): Promise<Uint8Array> {
41
+ this.log('fetching BLOCK for %c from %s', cid, provider.url)
42
+
43
+ options?.onProgress?.(new CustomProgressEvent('helia:block-brokers:query-provider:start', {
44
+ blockBroker: 'trustless-gateway',
45
+ provider: provider.url,
46
+ transport: 'http',
47
+ cid
48
+ }))
49
+
50
+ let block: Uint8Array
51
+
52
+ try {
53
+ block = await provider.getRawBlock(cid, options)
54
+ this.log.trace('got block for %c from %s', cid, provider.url)
55
+ } finally {
56
+ options?.onProgress?.(new CustomProgressEvent('helia:block-brokers:query-provider:end', {
57
+ blockBroker: 'trustless-gateway',
58
+ provider: provider.url,
59
+ transport: 'http',
60
+ cid
61
+ }))
62
+ }
63
+
64
+ await options.validateFn?.(block)
65
+
66
+ return block
67
+ }
68
+
69
+ async * findNewProviders (cid: CID, options: AbortOptions = {}): AsyncGenerator<TrustlessGateway> {
70
+ yield * findHttpGatewayProviders(cid, this.routing, this.logger, this.allowInsecure, this.allowLocal, { ...options, transformRequestInit: this.transformRequestInit })
71
+ }
72
+
73
+ toFilterKey (provider: TrustlessGateway): Uint8Array | string {
74
+ return provider.url.toString()
75
+ }
76
+
77
+ equals (providerA: TrustlessGateway, providerB: TrustlessGateway): boolean {
78
+ return providerA.url.toString() === providerB.url.toString()
79
+ }
80
+
81
+ async convertToProvider (provider: CID | Multiaddr | Multiaddr[], routing: string, options?: AbortOptions): Promise<TrustlessGateway | undefined> {
82
+ options?.signal?.throwIfAborted()
83
+
84
+ if (isCID(provider)) {
85
+ return
86
+ }
87
+
88
+ const httpAddresses = filterNonHTTPMultiaddrs(Array.isArray(provider) ? provider : [provider], this.allowInsecure, this.allowLocal)
89
+
90
+ if (httpAddresses.length === 0) {
91
+ return
92
+ }
93
+
94
+ // take first address?
95
+ // /ip4/x.x.x.x/tcp/31337/http
96
+ // /ip4/x.x.x.x/tcp/31337/https
97
+ // etc
98
+ const uri = multiaddrToUri(httpAddresses[0])
99
+
100
+ return new TrustlessGateway(uri, {
101
+ logger: this.logger,
102
+ transformRequestInit: this.transformRequestInit,
103
+ routing
104
+ })
105
+ }
106
+
107
+ emitFoundProviderProgressEvent (cid: CID, provider: TrustlessGateway, options: BlockRetrievalOptions<TrustlessGatewayGetBlockProgressEvents>): void {
108
+ options?.onProgress?.(new CustomProgressEvent<TrustlessGatewayProvider>('trustless-gateway:found-provider', {
109
+ type: 'trustless-gateway',
110
+ cid,
111
+ url: provider.url.toJSON(),
112
+ routing: provider.routing
113
+ }))
114
+ }
115
+ }
116
+
117
+ export function createTrustlessGatewaySession (components: TrustlessGatewaySessionComponents, init: CreateTrustlessGatewaySessionOptions): TrustlessGatewaySession {
118
+ return new TrustlessGatewaySession(components, init)
119
+ }