@helia/dnslink 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export declare const MAX_RECURSIVE_DEPTH = 32;
2
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,mBAAmB,KAAK,CAAA"}
@@ -0,0 +1,2 @@
1
+ export const MAX_RECURSIVE_DEPTH = 32;
2
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAA"}
@@ -0,0 +1,11 @@
1
+ import type { DNSLink as DNSLinkInterface, ResolveDNSLinkOptions, DNSLinkOptions, DNSLinkComponents, DNSLinkResult } from './index.js';
2
+ export declare class DNSLink implements DNSLinkInterface {
3
+ private readonly dns;
4
+ private readonly log;
5
+ private readonly namespaces;
6
+ constructor(components: DNSLinkComponents, init?: DNSLinkOptions);
7
+ resolve(domain: string, options?: ResolveDNSLinkOptions): Promise<DNSLinkResult>;
8
+ recursiveResolveDomain(domain: string, depth: number, options?: ResolveDNSLinkOptions): Promise<DNSLinkResult>;
9
+ recursiveResolveDnslink(domain: string, depth: number, options?: ResolveDNSLinkOptions): Promise<DNSLinkResult>;
10
+ }
11
+ //# sourceMappingURL=dnslink.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dnslink.d.ts","sourceRoot":"","sources":["../../src/dnslink.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,IAAI,gBAAgB,EAAE,qBAAqB,EAAE,cAAc,EAAE,iBAAiB,EAAE,aAAa,EAAoB,MAAM,YAAY,CAAA;AAIxJ,qBAAa,OAAQ,YAAW,gBAAgB;IAC9C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAK;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAQ;IAC5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkC;gBAEhD,UAAU,EAAE,iBAAiB,EAAE,IAAI,GAAE,cAAmB;IAU/D,OAAO,CAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,aAAa,CAAC;IAIrF,sBAAsB,CAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,aAAa,CAAC;IAkCnH,uBAAuB,CAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,OAAO,CAAC,aAAa,CAAC;CAoF3H"}
@@ -0,0 +1,120 @@
1
+ import { MAX_RECURSIVE_DEPTH, RecordType } from '@multiformats/dns';
2
+ import { DNSLinkNotFoundError } from './errors.js';
3
+ import { ipfs } from "./namespaces/ipfs.js";
4
+ import { ipns } from "./namespaces/ipns.js";
5
+ export class DNSLink {
6
+ dns;
7
+ log;
8
+ namespaces;
9
+ constructor(components, init = {}) {
10
+ this.dns = components.dns;
11
+ this.log = components.logger.forComponent('helia:dnslink');
12
+ this.namespaces = {
13
+ ipfs,
14
+ ipns,
15
+ ...init.namespaces
16
+ };
17
+ }
18
+ async resolve(domain, options = {}) {
19
+ return this.recursiveResolveDomain(domain, options.maxRecursiveDepth ?? MAX_RECURSIVE_DEPTH, options);
20
+ }
21
+ async recursiveResolveDomain(domain, depth, options = {}) {
22
+ if (depth === 0) {
23
+ throw new Error('recursion limit exceeded');
24
+ }
25
+ // the DNSLink spec says records MUST be stored on the `_dnslink.` subdomain
26
+ // so start looking for records there, we will fall back to the bare domain
27
+ // if none are found
28
+ if (!domain.startsWith('_dnslink.')) {
29
+ domain = `_dnslink.${domain}`;
30
+ }
31
+ try {
32
+ return await this.recursiveResolveDnslink(domain, depth, options);
33
+ }
34
+ catch (err) {
35
+ // If the code is not ENOTFOUND or ERR_DNSLINK_NOT_FOUND or ENODATA then throw the error
36
+ if (err.code !== 'ENOTFOUND' && err.code !== 'ENODATA' && err.name !== 'DNSLinkNotFoundError' && err.name !== 'NotFoundError') {
37
+ throw err;
38
+ }
39
+ if (domain.startsWith('_dnslink.')) {
40
+ // The supplied domain contains a _dnslink component
41
+ // Check the non-_dnslink domain
42
+ domain = domain.replace('_dnslink.', '');
43
+ }
44
+ else {
45
+ // Check the _dnslink subdomain
46
+ domain = `_dnslink.${domain}`;
47
+ }
48
+ // If this throws then we propagate the error
49
+ return this.recursiveResolveDnslink(domain, depth, options);
50
+ }
51
+ }
52
+ async recursiveResolveDnslink(domain, depth, options = {}) {
53
+ if (depth === 0) {
54
+ throw new Error('recursion limit exceeded');
55
+ }
56
+ this.log('query %s for TXT and CNAME records', domain);
57
+ const txtRecordsResponse = await this.dns.query(domain, {
58
+ ...options,
59
+ types: [
60
+ RecordType.TXT
61
+ ]
62
+ });
63
+ // sort the TXT records to ensure deterministic processing
64
+ const txtRecords = (txtRecordsResponse?.Answer ?? [])
65
+ .sort((a, b) => a.data.localeCompare(b.data));
66
+ this.log('found %d TXT records for %s', txtRecords.length, domain);
67
+ for (const answer of txtRecords) {
68
+ try {
69
+ let result = answer.data;
70
+ // strip leading and trailing " characters
71
+ if (result.startsWith('"') && result.endsWith('"')) {
72
+ result = result.substring(1, result.length - 1);
73
+ }
74
+ if (!result.startsWith('dnslink=')) {
75
+ // invalid record?
76
+ continue;
77
+ }
78
+ this.log('%s TXT %s', answer.name, result);
79
+ result = result.replace('dnslink=', '');
80
+ // result is now a `/ipfs/<cid>` or `/ipns/<cid>` string
81
+ const [, protocol, domainOrCID] = result.split('/'); // e.g. ["", "ipfs", "<cid>"]
82
+ if (protocol === 'dnslink') {
83
+ // if the result was another DNSLink domain, try to follow it
84
+ return await this.recursiveResolveDomain(domainOrCID, depth - 1, options);
85
+ }
86
+ const parser = this.namespaces[protocol];
87
+ if (parser == null) {
88
+ this.log('unknown protocol "%s" in DNSLink record for domain: %s', protocol, domain);
89
+ continue;
90
+ }
91
+ return parser.parse(result, answer);
92
+ }
93
+ catch (err) {
94
+ this.log.error('could not parse DNS link record for domain %s, %s', domain, answer.data, err);
95
+ }
96
+ }
97
+ // no dnslink records found, try CNAMEs
98
+ this.log('no DNSLink records found for %s, falling back to CNAME', domain);
99
+ const cnameRecordsResponse = await this.dns.query(domain, {
100
+ ...options,
101
+ types: [
102
+ RecordType.CNAME
103
+ ]
104
+ });
105
+ // sort the CNAME records to ensure deterministic processing
106
+ const cnameRecords = (cnameRecordsResponse?.Answer ?? [])
107
+ .sort((a, b) => a.data.localeCompare(b.data));
108
+ this.log('found %d CNAME records for %s', cnameRecords.length, domain);
109
+ for (const cname of cnameRecords) {
110
+ try {
111
+ return await this.recursiveResolveDomain(cname.data, depth - 1, options);
112
+ }
113
+ catch (err) {
114
+ this.log.error('domain %s cname %s had no DNSLink records - %e', domain, cname.data, err);
115
+ }
116
+ }
117
+ throw new DNSLinkNotFoundError(`No DNSLink records found for domain: ${domain}`);
118
+ }
119
+ }
120
+ //# sourceMappingURL=dnslink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dnslink.js","sourceRoot":"","sources":["../../src/dnslink.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export declare class DNSLinkNotFoundError extends Error {
2
+ static name: string;
3
+ constructor(message?: string);
4
+ }
5
+ export declare class InvalidNamespaceError extends Error {
6
+ static name: string;
7
+ constructor(message?: string);
8
+ }
9
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,oBAAqB,SAAQ,KAAK;IAC7C,MAAM,CAAC,IAAI,SAAyB;gBAEvB,OAAO,SAAsB;CAI3C;AAED,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,MAAM,CAAC,IAAI,SAA0B;gBAExB,OAAO,SAAsB;CAI3C"}
@@ -0,0 +1,15 @@
1
+ export class DNSLinkNotFoundError extends Error {
2
+ static name = 'DNSLinkNotFoundError';
3
+ constructor(message = 'DNSLink not found') {
4
+ super(message);
5
+ this.name = 'DNSLinkNotFoundError';
6
+ }
7
+ }
8
+ export class InvalidNamespaceError extends Error {
9
+ static name = 'InvalidNamespaceError';
10
+ constructor(message = 'Invalid namespace') {
11
+ super(message);
12
+ this.name = 'InvalidNamespaceError';
13
+ }
14
+ }
15
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC7C,MAAM,CAAC,IAAI,GAAG,sBAAsB,CAAA;IAEpC,YAAa,OAAO,GAAG,mBAAmB;QACxC,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAA;IACpC,CAAC;;AAGH,MAAM,OAAO,qBAAsB,SAAQ,KAAK;IAC9C,MAAM,CAAC,IAAI,GAAG,uBAAuB,CAAA;IAErC,YAAa,OAAO,GAAG,mBAAmB;QACxC,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAA;IACrC,CAAC"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * [DNSLink](https://dnslink.dev/) operations using a Helia node.
5
+ *
6
+ * @example Using custom DNS over HTTPS resolvers
7
+ *
8
+ * To use custom resolvers, configure Helia's `dns` option:
9
+ *
10
+ * ```TypeScript
11
+ * import { createHelia } from 'helia'
12
+ * import { dnsLink } from '@helia/dnslink'
13
+ * import { dns } from '@multiformats/dns'
14
+ * import { dnsOverHttps } from '@multiformats/dns/resolvers'
15
+ * import type { DefaultLibp2pServices } from 'helia'
16
+ * import type { Libp2p } from '@libp2p/interface'
17
+ *
18
+ * const node = await createHelia<Libp2p<DefaultLibp2pServices>>({
19
+ * dns: dns({
20
+ * resolvers: {
21
+ * '.': dnsOverHttps('https://private-dns-server.me/dns-query')
22
+ * }
23
+ * })
24
+ * })
25
+ * const name = dnsLink(node)
26
+ *
27
+ * const result = name.resolve('some-domain-with-dnslink-entry.com')
28
+ * ```
29
+ *
30
+ * @example Resolving a domain with a dnslink entry
31
+ *
32
+ * Calling `resolve` with the `@helia/dnslink` instance:
33
+ *
34
+ * ```TypeScript
35
+ * // resolve a CID from a TXT record in a DNS zone file, using the default
36
+ * // resolver for the current platform eg:
37
+ * // > dig _dnslink.ipfs.tech TXT
38
+ * // ;; ANSWER SECTION:
39
+ * // _dnslink.ipfs.tech. 60 IN CNAME _dnslink.ipfs-tech.on.fleek.co.
40
+ * // _dnslink.ipfs-tech.on.fleek.co. 120 IN TXT "dnslink=/ipfs/bafybe..."
41
+ *
42
+ * import { createHelia } from 'helia'
43
+ * import { dnsLink } from '@helia/dnslink'
44
+ *
45
+ * const node = await createHelia()
46
+ * const name = dnsLink(node)
47
+ *
48
+ * const { answer } = await name.resolve('blog.ipfs.tech')
49
+ *
50
+ * console.info(answer)
51
+ * // { data: '/ipfs/bafybe...' }
52
+ * ```
53
+ *
54
+ * @example Using DNS-Over-HTTPS
55
+ *
56
+ * This example uses the Mozilla provided RFC 1035 DNS over HTTPS service. This
57
+ * uses binary DNS records so requires extra dependencies to process the
58
+ * response which can increase browser bundle sizes.
59
+ *
60
+ * If this is a concern, use the DNS-JSON-Over-HTTPS resolver instead.
61
+ *
62
+ * ```TypeScript
63
+ * import { createHelia } from 'helia'
64
+ * import { dnsLink } from '@helia/dnslink'
65
+ * import { dns } from '@multiformats/dns'
66
+ * import { dnsOverHttps } from '@multiformats/dns/resolvers'
67
+ * import type { DefaultLibp2pServices } from 'helia'
68
+ * import type { Libp2p } from '@libp2p/interface'
69
+ *
70
+ * const node = await createHelia<Libp2p<DefaultLibp2pServices>>({
71
+ * dns: dns({
72
+ * resolvers: {
73
+ * '.': dnsOverHttps('https://mozilla.cloudflare-dns.com/dns-query')
74
+ * }
75
+ * })
76
+ * })
77
+ * const name = dnsLink(node)
78
+ *
79
+ * const result = await name.resolve('blog.ipfs.tech')
80
+ * ```
81
+ *
82
+ * @example Using DNS-JSON-Over-HTTPS
83
+ *
84
+ * DNS-JSON-Over-HTTPS resolvers use the RFC 8427 `application/dns-json` and can
85
+ * result in a smaller browser bundle due to the response being plain JSON.
86
+ *
87
+ * ```TypeScript
88
+ * import { createHelia } from 'helia'
89
+ * import { dnsLink } from '@helia/dnslink'
90
+ * import { dns } from '@multiformats/dns'
91
+ * import { dnsJsonOverHttps } from '@multiformats/dns/resolvers'
92
+ * import type { DefaultLibp2pServices } from 'helia'
93
+ * import type { Libp2p } from '@libp2p/interface'
94
+ *
95
+ * const node = await createHelia<Libp2p<DefaultLibp2pServices>>({
96
+ * dns: dns({
97
+ * resolvers: {
98
+ * '.': dnsJsonOverHttps('https://mozilla.cloudflare-dns.com/dns-query')
99
+ * }
100
+ * })
101
+ * })
102
+ * const name = dnsLink(node)
103
+ *
104
+ * const result = await name.resolve('blog.ipfs.tech')
105
+ * ```
106
+ */
107
+ import type { AbortOptions, ComponentLogger, PeerId } from '@libp2p/interface';
108
+ import type { Answer, DNS, ResolveDnsProgressEvents } from '@multiformats/dns';
109
+ import type { CID } from 'multiformats/cid';
110
+ import type { ProgressOptions } from 'progress-events';
111
+ export interface ResolveDNSLinkOptions extends AbortOptions, ProgressOptions<ResolveDnsProgressEvents> {
112
+ /**
113
+ * Do not query the network for the IPNS record
114
+ *
115
+ * @default false
116
+ */
117
+ offline?: boolean;
118
+ /**
119
+ * Do not use cached DNS entries
120
+ *
121
+ * @default false
122
+ */
123
+ nocache?: boolean;
124
+ /**
125
+ * When resolving DNSLink records that resolve to other DNSLink records, limit
126
+ * how many times we will recursively resolve them.
127
+ *
128
+ * @default 32
129
+ */
130
+ maxRecursiveDepth?: number;
131
+ }
132
+ export interface DNSLinkIPFSResult {
133
+ /**
134
+ * The resolved record
135
+ */
136
+ answer: Answer;
137
+ /**
138
+ * The IPFS namespace
139
+ */
140
+ namespace: 'ipfs';
141
+ /**
142
+ * The resolved value
143
+ */
144
+ cid: CID;
145
+ /**
146
+ * If the resolved value is an IPFS path, it will be present here
147
+ */
148
+ path: string;
149
+ }
150
+ export interface DNSLinkIPNSResult {
151
+ /**
152
+ * The resolved record
153
+ */
154
+ answer: Answer;
155
+ /**
156
+ * The IPFS namespace
157
+ */
158
+ namespace: 'ipns';
159
+ /**
160
+ * The resolved value
161
+ */
162
+ peerId: PeerId;
163
+ /**
164
+ * If the resolved value is an IPFS path, it will be present here
165
+ */
166
+ path: string;
167
+ }
168
+ export interface DNSLinkOtherResult {
169
+ /**
170
+ * The resolved record
171
+ */
172
+ answer: Answer;
173
+ /**
174
+ * The IPFS namespace
175
+ */
176
+ namespace: string;
177
+ }
178
+ export type DNSLinkResult = DNSLinkIPFSResult | DNSLinkIPNSResult | DNSLinkOtherResult;
179
+ export interface DNSLinkNamespace {
180
+ /**
181
+ * Return a result parsed from a DNSLink value
182
+ */
183
+ parse(value: string, answer: Answer): DNSLinkResult;
184
+ }
185
+ export interface DNSLink {
186
+ /**
187
+ * Resolve a CID from a dns-link style IPNS record
188
+ *
189
+ * @example
190
+ *
191
+ * ```TypeScript
192
+ * import { createHelia } from 'helia'
193
+ * import { dnsLink } from '@helia/dnslink'
194
+ *
195
+ * const helia = await createHelia()
196
+ * const name = dnsLink(helia)
197
+ *
198
+ * const result = await name.resolve('ipfs.io', {
199
+ * signal: AbortSignal.timeout(5_000)
200
+ * })
201
+ *
202
+ * console.info(result) // { answer: ..., value: ... }
203
+ * ```
204
+ */
205
+ resolve(domain: string, options?: ResolveDNSLinkOptions): Promise<DNSLinkResult>;
206
+ }
207
+ export interface DNSLinkComponents {
208
+ dns: DNS;
209
+ logger: ComponentLogger;
210
+ }
211
+ export interface DNSLinkOptions {
212
+ /**
213
+ * By default `/ipfs/...`, `/ipns/...` and `/dnslink/...` record values are
214
+ * supported - to support other prefixes pass other value parsers here
215
+ */
216
+ namespaces?: Record<string, DNSLinkNamespace>;
217
+ }
218
+ export declare function dnsLink(components: DNSLinkComponents, options?: DNSLinkOptions): DNSLink;
219
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyGG;AAGH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAA;AAC9E,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAC3C,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AAEtD,MAAM,WAAW,qBAAsB,SAAQ,YAAY,EAAE,eAAe,CAAC,wBAAwB,CAAC;IACpG;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;IAEjB;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,GAAG,EAAE,GAAG,CAAA;IAER;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,iBAAiB;IAChC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;IAEjB;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,kBAAkB;IACjC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAA;IAEd;;OAEG;IACH,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,MAAM,aAAa,GAAG,iBAAiB,GAAG,iBAAiB,GAAG,kBAAkB,CAAA;AAEtF,MAAM,WAAW,gBAAgB;IAC/B;;OAEG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,aAAa,CAAA;CACpD;AAED,MAAM,WAAW,OAAO;IACtB;;;;;;;;;;;;;;;;;;OAkBG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,aAAa,CAAC,CAAA;CACjF;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,eAAe,CAAA;CACxB;AAED,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAA;CAC9C;AAED,wBAAgB,OAAO,CAAE,UAAU,EAAE,iBAAiB,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO,CAE7F"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @packageDocumentation
3
+ *
4
+ * [DNSLink](https://dnslink.dev/) operations using a Helia node.
5
+ *
6
+ * @example Using custom DNS over HTTPS resolvers
7
+ *
8
+ * To use custom resolvers, configure Helia's `dns` option:
9
+ *
10
+ * ```TypeScript
11
+ * import { createHelia } from 'helia'
12
+ * import { dnsLink } from '@helia/dnslink'
13
+ * import { dns } from '@multiformats/dns'
14
+ * import { dnsOverHttps } from '@multiformats/dns/resolvers'
15
+ * import type { DefaultLibp2pServices } from 'helia'
16
+ * import type { Libp2p } from '@libp2p/interface'
17
+ *
18
+ * const node = await createHelia<Libp2p<DefaultLibp2pServices>>({
19
+ * dns: dns({
20
+ * resolvers: {
21
+ * '.': dnsOverHttps('https://private-dns-server.me/dns-query')
22
+ * }
23
+ * })
24
+ * })
25
+ * const name = dnsLink(node)
26
+ *
27
+ * const result = name.resolve('some-domain-with-dnslink-entry.com')
28
+ * ```
29
+ *
30
+ * @example Resolving a domain with a dnslink entry
31
+ *
32
+ * Calling `resolve` with the `@helia/dnslink` instance:
33
+ *
34
+ * ```TypeScript
35
+ * // resolve a CID from a TXT record in a DNS zone file, using the default
36
+ * // resolver for the current platform eg:
37
+ * // > dig _dnslink.ipfs.tech TXT
38
+ * // ;; ANSWER SECTION:
39
+ * // _dnslink.ipfs.tech. 60 IN CNAME _dnslink.ipfs-tech.on.fleek.co.
40
+ * // _dnslink.ipfs-tech.on.fleek.co. 120 IN TXT "dnslink=/ipfs/bafybe..."
41
+ *
42
+ * import { createHelia } from 'helia'
43
+ * import { dnsLink } from '@helia/dnslink'
44
+ *
45
+ * const node = await createHelia()
46
+ * const name = dnsLink(node)
47
+ *
48
+ * const { answer } = await name.resolve('blog.ipfs.tech')
49
+ *
50
+ * console.info(answer)
51
+ * // { data: '/ipfs/bafybe...' }
52
+ * ```
53
+ *
54
+ * @example Using DNS-Over-HTTPS
55
+ *
56
+ * This example uses the Mozilla provided RFC 1035 DNS over HTTPS service. This
57
+ * uses binary DNS records so requires extra dependencies to process the
58
+ * response which can increase browser bundle sizes.
59
+ *
60
+ * If this is a concern, use the DNS-JSON-Over-HTTPS resolver instead.
61
+ *
62
+ * ```TypeScript
63
+ * import { createHelia } from 'helia'
64
+ * import { dnsLink } from '@helia/dnslink'
65
+ * import { dns } from '@multiformats/dns'
66
+ * import { dnsOverHttps } from '@multiformats/dns/resolvers'
67
+ * import type { DefaultLibp2pServices } from 'helia'
68
+ * import type { Libp2p } from '@libp2p/interface'
69
+ *
70
+ * const node = await createHelia<Libp2p<DefaultLibp2pServices>>({
71
+ * dns: dns({
72
+ * resolvers: {
73
+ * '.': dnsOverHttps('https://mozilla.cloudflare-dns.com/dns-query')
74
+ * }
75
+ * })
76
+ * })
77
+ * const name = dnsLink(node)
78
+ *
79
+ * const result = await name.resolve('blog.ipfs.tech')
80
+ * ```
81
+ *
82
+ * @example Using DNS-JSON-Over-HTTPS
83
+ *
84
+ * DNS-JSON-Over-HTTPS resolvers use the RFC 8427 `application/dns-json` and can
85
+ * result in a smaller browser bundle due to the response being plain JSON.
86
+ *
87
+ * ```TypeScript
88
+ * import { createHelia } from 'helia'
89
+ * import { dnsLink } from '@helia/dnslink'
90
+ * import { dns } from '@multiformats/dns'
91
+ * import { dnsJsonOverHttps } from '@multiformats/dns/resolvers'
92
+ * import type { DefaultLibp2pServices } from 'helia'
93
+ * import type { Libp2p } from '@libp2p/interface'
94
+ *
95
+ * const node = await createHelia<Libp2p<DefaultLibp2pServices>>({
96
+ * dns: dns({
97
+ * resolvers: {
98
+ * '.': dnsJsonOverHttps('https://mozilla.cloudflare-dns.com/dns-query')
99
+ * }
100
+ * })
101
+ * })
102
+ * const name = dnsLink(node)
103
+ *
104
+ * const result = await name.resolve('blog.ipfs.tech')
105
+ * ```
106
+ */
107
+ import { DNSLink as DNSLinkClass } from './dnslink.js';
108
+ export function dnsLink(components, options = {}) {
109
+ return new DNSLinkClass(components, options);
110
+ }
111
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyGG;AAEH,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,cAAc,CAAA;AAmItD,MAAM,UAAU,OAAO,CAAE,UAA6B,EAAE,UAA0B,EAAE;IAClF,OAAO,IAAI,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;AAC9C,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { DNSLinkNamespace } from '../index.js';
2
+ export declare const ipfs: DNSLinkNamespace;
3
+ //# sourceMappingURL=ipfs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipfs.d.ts","sourceRoot":"","sources":["../../../src/namespaces/ipfs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGlE,eAAO,MAAM,IAAI,EAAE,gBAgBlB,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { CID } from 'multiformats/cid';
2
+ import { InvalidNamespaceError } from "../errors.js";
3
+ export const ipfs = {
4
+ parse: (value, answer) => {
5
+ const [, protocol, cid, ...rest] = value.split('/');
6
+ if (protocol !== 'ipfs') {
7
+ throw new InvalidNamespaceError(`Namespace ${protocol} was not "ipfs"`);
8
+ }
9
+ // if the result is a CID, we've reached the end of the recursion
10
+ return {
11
+ namespace: 'ipfs',
12
+ cid: CID.parse(cid),
13
+ path: rest.length > 0 ? `/${rest.join('/')}` : '',
14
+ answer
15
+ };
16
+ }
17
+ };
18
+ //# sourceMappingURL=ipfs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipfs.js","sourceRoot":"","sources":["../../../src/namespaces/ipfs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AACtC,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAIpD,MAAM,CAAC,MAAM,IAAI,GAAqB;IACpC,KAAK,EAAE,CAAC,KAAa,EAAE,MAAc,EAAiB,EAAE;QACtD,MAAM,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEnD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,qBAAqB,CAAC,aAAa,QAAQ,iBAAiB,CAAC,CAAA;QACzE,CAAC;QAED,iEAAiE;QACjE,OAAO;YACL,SAAS,EAAE,MAAM;YACjB,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC;YACnB,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YACjD,MAAM;SACP,CAAA;IACH,CAAC;CACF,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { DNSLinkNamespace } from '../index.js';
2
+ export declare const ipns: DNSLinkNamespace;
3
+ //# sourceMappingURL=ipns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipns.d.ts","sourceRoot":"","sources":["../../../src/namespaces/ipns.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAiB,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAGlE,eAAO,MAAM,IAAI,EAAE,gBAgBlB,CAAA"}
@@ -0,0 +1,18 @@
1
+ import { peerIdFromString } from '@libp2p/peer-id';
2
+ import { InvalidNamespaceError } from "../errors.js";
3
+ export const ipns = {
4
+ parse: (value, answer) => {
5
+ const [, protocol, peerId, ...rest] = value.split('/');
6
+ if (protocol !== 'ipns') {
7
+ throw new InvalidNamespaceError(`Namespace ${protocol} was not "ipns"`);
8
+ }
9
+ // if the result is a CID, we've reached the end of the recursion
10
+ return {
11
+ namespace: 'ipns',
12
+ peerId: peerIdFromString(peerId),
13
+ path: rest.length > 0 ? `/${rest.join('/')}` : '',
14
+ answer
15
+ };
16
+ }
17
+ };
18
+ //# sourceMappingURL=ipns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipns.js","sourceRoot":"","sources":["../../../src/namespaces/ipns.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAClD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAA;AAIpD,MAAM,CAAC,MAAM,IAAI,GAAqB;IACpC,KAAK,EAAE,CAAC,KAAa,EAAE,MAAc,EAAiB,EAAE;QACtD,MAAM,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAEtD,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;YACxB,MAAM,IAAI,qBAAqB,CAAC,aAAa,QAAQ,iBAAiB,CAAC,CAAA;QACzE,CAAC;QAED,iEAAiE;QACjE,OAAO;YACL,SAAS,EAAE,MAAM;YACjB,MAAM,EAAE,gBAAgB,CAAC,MAAM,CAAC;YAChC,IAAI,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE;YACjD,MAAM;SACP,CAAA;IACH,CAAC;CACF,CAAA"}
@@ -0,0 +1,22 @@
1
+ {
2
+ "DNSLink": "https://ipfs.github.io/helia/interfaces/DNSLink.html",
3
+ ".:DNSLink": "https://ipfs.github.io/helia/interfaces/DNSLink.html",
4
+ "DNSLinkComponents": "https://ipfs.github.io/helia/interfaces/DNSLinkComponents.html",
5
+ ".:DNSLinkComponents": "https://ipfs.github.io/helia/interfaces/DNSLinkComponents.html",
6
+ "DNSLinkIPFSResult": "https://ipfs.github.io/helia/interfaces/DNSLinkIPFSResult.html",
7
+ ".:DNSLinkIPFSResult": "https://ipfs.github.io/helia/interfaces/DNSLinkIPFSResult.html",
8
+ "DNSLinkIPNSResult": "https://ipfs.github.io/helia/interfaces/DNSLinkIPNSResult.html",
9
+ ".:DNSLinkIPNSResult": "https://ipfs.github.io/helia/interfaces/DNSLinkIPNSResult.html",
10
+ "DNSLinkNamespace": "https://ipfs.github.io/helia/interfaces/DNSLinkNamespace.html",
11
+ ".:DNSLinkNamespace": "https://ipfs.github.io/helia/interfaces/DNSLinkNamespace.html",
12
+ "DNSLinkOptions": "https://ipfs.github.io/helia/interfaces/DNSLinkOptions.html",
13
+ ".:DNSLinkOptions": "https://ipfs.github.io/helia/interfaces/DNSLinkOptions.html",
14
+ "DNSLinkOtherResult": "https://ipfs.github.io/helia/interfaces/DNSLinkOtherResult.html",
15
+ ".:DNSLinkOtherResult": "https://ipfs.github.io/helia/interfaces/DNSLinkOtherResult.html",
16
+ "ResolveDNSLinkOptions": "https://ipfs.github.io/helia/interfaces/ResolveDNSLinkOptions.html",
17
+ ".:ResolveDNSLinkOptions": "https://ipfs.github.io/helia/interfaces/ResolveDNSLinkOptions.html",
18
+ "DNSLinkResult": "https://ipfs.github.io/helia/types/DNSLinkResult.html",
19
+ ".:DNSLinkResult": "https://ipfs.github.io/helia/types/DNSLinkResult.html",
20
+ "dnsLink": "https://ipfs.github.io/helia/functions/dnsLink.html",
21
+ ".:dnsLink": "https://ipfs.github.io/helia/functions/dnsLink.html"
22
+ }