kirin-dns 0.1.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/kirin_dns.d.ts ADDED
@@ -0,0 +1,67 @@
1
+ /**
2
+ * KirinDNS Resolution Protocol (ADRP) — TypeScript Type Definitions
3
+ *
4
+ * @module kirin-dns
5
+ */
6
+
7
+ /** Recognized protocol keys in an ADRP TXT record. */
8
+ export type AdrpKey = 'http' | 'https' | 'ws' | 'wss';
9
+
10
+ /**
11
+ * Resolved service ports for a KirinDNS-enabled domain.
12
+ * All four keys are always present — either from a valid ADRP record
13
+ * or the standard IANA fallback values.
14
+ */
15
+ export interface ResolvedPorts {
16
+ /** HTTP port (default 80). */
17
+ http: number;
18
+ /** HTTPS port (default 443). */
19
+ https: number;
20
+ /** WebSocket port (default 80). */
21
+ ws: number;
22
+ /** Secure WebSocket port (default 443). */
23
+ wss: number;
24
+ }
25
+
26
+ /**
27
+ * Standard IANA fallback ports.
28
+ * Used when no valid ADRP TXT record is found for the domain.
29
+ */
30
+ export const FALLBACK_PORTS: Readonly<ResolvedPorts>;
31
+
32
+ /**
33
+ * Recognized ADRP keys.
34
+ */
35
+ export const RECOGNIZED_KEYS: ReadonlySet<AdrpKey>;
36
+
37
+ /**
38
+ * Validate a parsed JSON object as a valid ADRP record.
39
+ *
40
+ * Rules (spec §3.1):
41
+ * - All values for recognized keys MUST be integers in range [1, 65535].
42
+ * - At least one recognized key MUST be present.
43
+ * - Unknown keys are silently ignored.
44
+ *
45
+ * @param data - Parsed JSON object to validate.
46
+ * @returns `true` if the record is a valid ADRP record.
47
+ */
48
+ export function validateKirinDnsRecord(data: unknown): data is Partial<Record<AdrpKey, number>>;
49
+
50
+ /**
51
+ * Parse a single TXT record string as JSON and validate it as an ADRP record.
52
+ *
53
+ * @param text - Raw TXT record string.
54
+ * @returns Parsed record (only recognized keys), or `null` if invalid.
55
+ */
56
+ export function parseTxtValue(text: string): Partial<Record<AdrpKey, number>> | null;
57
+
58
+ /**
59
+ * Resolve the KirinDNS ports for a given domain.
60
+ *
61
+ * Queries DNS TXT records and returns the first valid ADRP record found.
62
+ * Falls back to standard IANA ports if no valid record exists.
63
+ *
64
+ * @param domain - Domain name to query (e.g. "alice.kirinnet.org").
65
+ * @returns Promise resolving to the port mapping.
66
+ */
67
+ export function resolve_kirin_dns(domain: string): Promise<ResolvedPorts>;
package/kirin_dns.js ADDED
@@ -0,0 +1,178 @@
1
+ /**
2
+ * KirinDNS Resolution Protocol (ADRP) — Node.js Client Library
3
+ *
4
+ * Implements ADRP as defined in 01_Standard/spec_v1.md.
5
+ *
6
+ * Resolution algorithm:
7
+ * 1. Query TXT records for the target domain using dns.resolveTxt().
8
+ * 2. Iterate through each TXT record; attempt to parse as JSON.
9
+ * 3. The first record that parses as valid JSON and contains at least one
10
+ * recognized key (http, https, ws, wss) is the ADRP response.
11
+ * 4. If no valid ADRP record is found, return the standard fallback ports.
12
+ *
13
+ * NOTE ON BROWSER USAGE:
14
+ * Browsers cannot directly query DNS TXT records. This library is intended
15
+ * for Node.js (server-side) use. For browser-based ADRP resolution, use the
16
+ * Service Worker approach described in Phase 3 (Browser Extension), which
17
+ * proxies TXT queries through a DoH (DNS-over-HTTPS) endpoint.
18
+ *
19
+ * NOTE ON SECURITY:
20
+ * Node.js's built-in dns module uses unencrypted DNS by default. For
21
+ * production ADRP queries, configure a DoH/DoT resolver in front of this
22
+ * library, or use a library like 'native-dns' with DoT support.
23
+ * See 01_Standard/spec_v1.md Section 4.3 for the security requirements.
24
+ *
25
+ * Example usage:
26
+ * const { resolve_kirin_dns } = require('./kirin_dns');
27
+ *
28
+ * (async () => {
29
+ * const ports = await resolve_kirin_dns('example.com');
30
+ * console.log(ports);
31
+ * // => { http: 80, https: 8443 } (if ADRP record exists)
32
+ * // => { http: 80, https: 443 } (fallback)
33
+ * })();
34
+ */
35
+
36
+ const dns = require('dns');
37
+
38
+ // Recognized ADRP keys (spec Section 3.1.1)
39
+ const RECOGNIZED_KEYS = new Set(['http', 'https', 'ws', 'wss']);
40
+
41
+ // Fallback ports (spec Section 3.2, Step 5)
42
+ const FALLBACK_PORTS = {
43
+ http: 80,
44
+ https: 443,
45
+ ws: 80,
46
+ wss: 443,
47
+ };
48
+
49
+ /**
50
+ * Validate an ADRP JSON payload against the spec (Section 3.1).
51
+ *
52
+ * Rules:
53
+ * - All values for recognized keys MUST be integers in the range 1-65535.
54
+ * - At least one recognized key MUST be present.
55
+ * - Unknown keys are silently ignored.
56
+ *
57
+ * @param {object} data - Parsed JSON object to validate.
58
+ * @returns {boolean} True if the record is a valid ADRP record.
59
+ */
60
+ function validateKirinDnsRecord(data) {
61
+ if (typeof data !== 'object' || data === null || Array.isArray(data)) {
62
+ return false;
63
+ }
64
+
65
+ let recognizedKeyPresent = false;
66
+
67
+ for (const [key, value] of Object.entries(data)) {
68
+ if (RECOGNIZED_KEYS.has(key)) {
69
+ recognizedKeyPresent = true;
70
+ // Must be an integer in range 1-65535
71
+ if (!Number.isInteger(value) || value < 1 || value > 65535) {
72
+ return false;
73
+ }
74
+ }
75
+ }
76
+
77
+ return recognizedKeyPresent;
78
+ }
79
+
80
+ /**
81
+ * Parse a single TXT record string as JSON and validate it as an ADRP record.
82
+ *
83
+ * The spec (Section 3.1.1) requires the JSON object to be the sole content
84
+ * of the TXT character string.
85
+ *
86
+ * @param {string} text - The TXT record string.
87
+ * @returns {object|null} Parsed ADRP record, or null if not valid.
88
+ */
89
+ function parseTxtValue(text) {
90
+ const trimmed = text.trim();
91
+
92
+ let parsed;
93
+ try {
94
+ parsed = JSON.parse(trimmed);
95
+ } catch {
96
+ return null; // Not valid JSON — skip this record
97
+ }
98
+
99
+ if (validateKirinDnsRecord(parsed)) {
100
+ return parsed;
101
+ }
102
+ return null; // Valid JSON but not a valid ADRP record
103
+ }
104
+
105
+ /**
106
+ * Resolve the KirinDNS ports for a given domain.
107
+ *
108
+ * Returns a Promise that resolves to an object mapping protocol keys to
109
+ * port numbers. If the domain has no valid ADRP TXT record, the standard
110
+ * fallback ports are returned.
111
+ *
112
+ * @param {string} domain - The domain name to query.
113
+ * @returns {Promise<object>} Port mapping object.
114
+ */
115
+ async function resolve_kirin_dns(domain) {
116
+ // Start with full fallback; recognized keys will be overwritten if found.
117
+ const result = { ...FALLBACK_PORTS };
118
+
119
+ let txtRecords;
120
+ try {
121
+ txtRecords = await dns.resolveTxt(domain);
122
+ } catch (err) {
123
+ // ENOTFOUND (domain does not exist), ENODATA (no TXT records),
124
+ // or other DNS errors — fall back to defaults.
125
+ return result;
126
+ }
127
+
128
+ // Aggregate and parse (spec Section 3.1.2, "first valid" rule)
129
+ for (const record of txtRecords) {
130
+ // dns.resolveTxt() returns an array of arrays of strings.
131
+ // Each inner array is a single TXT record that may be split across
132
+ // multiple strings; join them to reconstruct the full value.
133
+ const txtValue = record.join('');
134
+ const parsed = parseTxtValue(txtValue);
135
+
136
+ if (parsed !== null) {
137
+ // Found the first valid ADRP record.
138
+ // Overwrite only the keys present in the record; missing keys
139
+ // retain their fallback values.
140
+ Object.assign(result, parsed);
141
+ return result;
142
+ }
143
+ }
144
+
145
+ // No valid ADRP record found — return fallback.
146
+ return result;
147
+ }
148
+
149
+ module.exports = { resolve_kirin_dns };
150
+
151
+ // ---------------------------------------------------------------------------
152
+ // Self-test (run with: node aura_dns.js)
153
+ // ---------------------------------------------------------------------------
154
+ if (require.main === module) {
155
+ (async () => {
156
+ // Example: query a real domain (will likely return fallback ports)
157
+ const testDomain = 'example.com';
158
+ const ports = await resolve_kirin_dns(testDomain);
159
+ console.log(`ADRP query for ${testDomain}:`, ports);
160
+
161
+ // Example: NXDOMAIN should return fallback
162
+ const fallback = await resolve_kirin_dns('nonexistent.invalid');
163
+ console.log(`ADRP query for nonexistent.invalid:`, fallback);
164
+
165
+ // Internal unit tests
166
+ console.assert(validateKirinDnsRecord({ http: 8080, https: 8443 }) === true, 'valid record');
167
+ console.assert(validateKirinDnsRecord({ https: 443 }) === true, 'single key');
168
+ console.assert(validateKirinDnsRecord({ ws: 0 }) === false, 'port out of range (0)');
169
+ console.assert(validateKirinDnsRecord({ ws: 65536 }) === false, 'port out of range (65536)');
170
+ console.assert(validateKirinDnsRecord({ ws: '80' }) === false, 'port not an integer');
171
+ console.assert(validateKirinDnsRecord({ unknown: 80 }) === false, 'no recognized key');
172
+ console.assert(validateKirinDnsRecord({}) === false, 'empty object');
173
+ console.assert(validateKirinDnsRecord('not an object') === false, 'wrong type');
174
+ console.assert(validateKirinDnsRecord(null) === false, 'null');
175
+ console.assert(validateKirinDnsRecord([1, 2]) === false, 'array');
176
+ console.log('Internal unit tests passed.');
177
+ })();
178
+ }
package/package.json ADDED
@@ -0,0 +1,25 @@
1
+ {
2
+ "name": "kirin-dns",
3
+ "version": "0.1.0",
4
+ "description": "KirinDNS (ADRP) — Port-aware DNS resolution client library",
5
+ "main": "kirin_dns.js",
6
+ "types": "kirin_dns.d.ts",
7
+ "files": [
8
+ "kirin_dns.js",
9
+ "kirin_dns.d.ts"
10
+ ],
11
+ "keywords": ["dns", "adrp", "kirindns", "port-discovery", "web3"],
12
+ "author": "kirin-yucall <kirin.yucall@gmail.com>",
13
+ "license": "MIT",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "https://github.com/kirin-yucall/KirinNet.git"
17
+ },
18
+ "bugs": {
19
+ "url": "https://github.com/kirin-yucall/KirinNet/issues"
20
+ },
21
+ "homepage": "https://github.com/kirin-yucall/KirinNet",
22
+ "engines": {
23
+ "node": ">=18"
24
+ }
25
+ }