@nictool/dns-resource-record 1.6.0 → 1.7.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +45 -6
  2. package/README.md +328 -198
  3. package/dist/dns-rr.min.js +26 -0
  4. package/dist/dns-rr.min.js.map +7 -0
  5. package/index.js +12 -11
  6. package/lib/binary.js +108 -0
  7. package/lib/bind.js +94 -0
  8. package/lib/dns-query.js +67 -0
  9. package/lib/tinydns.js +128 -44
  10. package/lib/wire.js +519 -0
  11. package/package.json +29 -10
  12. package/rr/TEMPLATE.js +124 -0
  13. package/rr/a.js +8 -48
  14. package/rr/aaaa.js +13 -80
  15. package/rr/apl.js +123 -27
  16. package/rr/caa.js +27 -50
  17. package/rr/cert.js +58 -87
  18. package/rr/cname.js +7 -63
  19. package/rr/dhcid.js +20 -30
  20. package/rr/dname.js +9 -36
  21. package/rr/dnskey.js +38 -32
  22. package/rr/ds.js +43 -57
  23. package/rr/hinfo.js +21 -40
  24. package/rr/hip.js +88 -26
  25. package/rr/https.js +28 -40
  26. package/rr/ipseckey.js +97 -18
  27. package/rr/key.js +39 -29
  28. package/rr/kx.js +16 -27
  29. package/rr/loc.js +42 -12
  30. package/rr/mx.js +16 -51
  31. package/rr/naptr.js +58 -33
  32. package/rr/ns.js +8 -36
  33. package/rr/nsec.js +89 -18
  34. package/rr/nsec3.js +62 -26
  35. package/rr/nsec3param.js +56 -53
  36. package/rr/nxt.js +57 -18
  37. package/rr/openpgpkey.js +24 -30
  38. package/rr/ptr.js +7 -47
  39. package/rr/rp.js +17 -32
  40. package/rr/rrsig.js +80 -85
  41. package/rr/sig.js +70 -45
  42. package/rr/smimea.js +33 -33
  43. package/rr/soa.js +31 -49
  44. package/rr/spf.js +10 -17
  45. package/rr/srv.js +22 -62
  46. package/rr/sshfp.js +25 -53
  47. package/rr/svcb.js +27 -40
  48. package/rr/tlsa.js +34 -34
  49. package/rr/tsig.js +87 -24
  50. package/rr/txt.js +40 -59
  51. package/rr/uri.js +19 -29
  52. package/rr/wks.js +154 -22
  53. package/rr.js +290 -109
  54. package/lib/readme.js +0 -84
package/CHANGELOG.md CHANGED
@@ -4,17 +4,54 @@ Notable changes to this project are documented in this file.
4
4
 
5
5
  #### Unreleased
6
6
 
7
- ### [1.6.0] - 2026-03-26
7
+ ### [1.7.0] - 2026-04-20
8
8
 
9
- #### Changed
9
+ #### Fixes
10
10
 
11
- - feat(getCanonical): added to RRs where missing
12
- - feat(toWire): added wire format export
13
- - feat: add getTags() to all RR types
11
+ - rr/txt: chunk by UTF-8 bytes (vs ASCII)
12
+ - rr/rrsig: validate "type covered" correctly
13
+
14
+ #### Changes
15
+
16
+ - RR is strictly a factory now
17
+ - no longer returns a different object based on bindLine or tinyLine
18
+ - doc(CAA, DS): added RFC 9619
19
+ - openpgpkey: reject keys with non-ASCII
20
+ - tinydns: name any out-of-range chars in error msg
21
+ - fromBind: use a tokenizing parser (vs regexes)
22
+
23
+ #### Additions
24
+
25
+ - add rr/TEMPLATE.js with lots of docs
26
+ - declarative rdataFields to remove lots of boilerplate from rr/all
27
+ - browser compat enhancements
28
+ - rollup dns-rr.min.js + min.js.map
29
+ - add `static typeName` as constructor.name doesn't survive minification
30
+ - feat(lib/binary): add shared binary functions
31
+ - change: replace `Buffer` with Uint8Array, DataView, and math
32
+ - feat(lib/wire): add wire format helpers
33
+ - feat(fromWire): added wire format parsers
34
+ - used to round-trip DNS and validate parsing & formatting
35
+ - feat(fromBind): use a parser (vs regexes)
36
+ - test: add dnsLiveTests, test `toWire()` against live NSD & tinydns
37
+ - uncovered edge cases in round trips between formats
38
+
39
+ ### [1.6.1] - 2026-04-20
40
+
41
+ - doc(README): add wire export format
42
+ - ci: split coverage to new GHA file, trigger on push to main
43
+
44
+ ### [1.6.0] - 2026-03-26
45
+
46
+ - feat(toWire): add wire export format to every RR, fixes #23
47
+ - feat(getTags): added to all RR types
14
48
  - values: common, obsolete, security, dnssec
15
- - doc(README): categorize RR types.
49
+ - feat(getCanonical): added to RRs where missing
16
50
  - added RFCs to: AAAA 5952, NAPTR 4848, SIG 3755, TLSA 7671
17
51
  - TXT: 4408, 6376, 7208
52
+ - doc(README): categorize RR types.
53
+ - doc(README): generate the supported RRs table
54
+ - test: add tests for toWire, getCanonical, getTags
18
55
 
19
56
  ### [1.5.0] - 2026-03-22
20
57
 
@@ -379,3 +416,5 @@ Notable changes to this project are documented in this file.
379
416
  [1.4.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.4.0
380
417
  [1.5.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.5.0
381
418
  [1.6.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.6.0
419
+ [1.6.1]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.6.1
420
+ [1.7.0]: https://github.com/NicTool/dns-resource-record/releases/tag/v1.7.0
package/README.md CHANGED
@@ -1,266 +1,396 @@
1
- [![Module Tests](https://github.com/NicTool/dns-resource-record/actions/workflows/ci.yml/badge.svg)](https://github.com/NicTool/dns-resource-record/actions/workflows/ci.yml)
2
- [![Coverage Status](https://coveralls.io/repos/github/NicTool/dns-resource-record/badge.svg?branch=master)](https://coveralls.io/github/NicTool/dns-resource-record?branch=master)
1
+ [![Module Tests][ci-img]][ci-url]
2
+ [![Test Coverage][cov-img]][cov-url]
3
3
 
4
4
  # dns-resource-record
5
5
 
6
- DNS resource record parser, validator, importer, and exporter for node.js & browsers.
6
+ DNS resource record parser, validator, importer, and exporter for node.js & browsers
7
7
 
8
- ## SYNOPSIS
8
+ **Quick Links:** [Getting Started](#getting-started) | [API Reference](#api-reference) | [Browser/CDN](#browser--cdn) | [Supported Records](#supported-records) | [Contributing](#development)
9
9
 
10
- This module is used to:
10
+ ## Overview
11
11
 
12
- - validate well formedness and RFC compliance of DNS resource records
13
- - import RRs to and from the following formats:
12
+ This module validates, imports, and exports DNS resource records (RRs) with rigorous RFC compliance and robust test coverage.
14
13
 
15
- | **RR format** | **import** | **export** |
16
- | :------------------------------------------------------: | :----------------: | :----------------: |
17
- | **JSON** | :white_check_mark: | :white_check_mark: |
18
- | **[BIND](https://www.isc.org/bind/)** | :white_check_mark: | :white_check_mark: |
19
- | **[Tinydns](https://cr.yp.to/djbdns/tinydns-data.html)** | :white_check_mark: | :white_check_mark: |
20
- | **MaraDNS** | | :white_check_mark: |
21
- | **JS** | :white_check_mark: | :white_check_mark: |
22
- | **PowerDNS** | | |
14
+ **What you can do:**
23
15
 
24
- This package intends to import and export RFC compliant DNS resource records. Please [raise an issue](https://github.com/NicTool/dns-resource-record/issues) if a valid resource record fails to pass or an invalid resource record passes.
16
+ - **Validate** DNS records for RFC compliance and well-formedness
17
+ - **Parse/Import** records from BIND zone files, tinydns data files, or JS objects
18
+ - **Export** records to BIND, tinydns, MaraDNS, JSON, or wire format
19
+ - **Manipulate** validated records with type-safe setters
20
+ - **Convert** between formats seamlessly (e.g., tinydns → BIND -> wire)
25
21
 
26
- This package is for working with _individual_ Resource Records. For working with zones of RRs, use [dns-zone](https://github.com/NicTool/dns-zone).
22
+ **Scope:** This package handles individual Resource Records. For zone file operations, see [dns-zone](https://github.com/NicTool/dns-zone).
27
23
 
28
- ## USAGE
24
+ **Quality:** RFC compliance is a first-class concern. If you encounter a valid RR that fails to parse or an invalid RR that passes validation, please [open an issue](https://github.com/NicTool/dns-resource-record/issues).
29
25
 
30
- Load the index for access to all RR types:
26
+ ## Supported Records
27
+
28
+ This module supports all current DNS RRs in active use on the internet.
29
+
30
+ | Usage | **Resource Record Types** |
31
+ | :-----------: | :-----------------------------------------------------------: |
32
+ | _Common_ | A, AAAA, CNAME, HTTPS, MX, NS, PTR, SOA, SRV, TXT |
33
+ | _Less Common_ | APL, CERT, DHCID, DNAME, HIP, KX, LOC, NAPTR, SVCB, TSIG, URI |
34
+ | _Security_ | CAA, IPSECKEY, OPENPGPKEY, SMIMEA, SSHFP, TLSA |
35
+ | _DNSSEC_ | DNSKEY, DS, NSEC, NSEC3, NSEC3PARAM, RRSIG |
36
+ | _Obsolete_ | HINFO, KEY, NXT, RP, SIG, SPF, WKS |
37
+
38
+ ## Getting Started
39
+
40
+ ### Installation
41
+
42
+ ```sh
43
+ npm install @nictool/dns-resource-record
44
+ ```
45
+
46
+ ### Validation
47
+
48
+ Validate an A record:
31
49
 
32
50
  ```js
33
51
  import * as RR from '@nictool/dns-resource-record'
52
+
53
+ const validA = new RR.A({
54
+ owner: 'example.com.',
55
+ address: '192.0.2.1',
56
+ ttl: 3600,
57
+ })
58
+
59
+ console.log(validA.toBind())
60
+ // example.com 3600 IN A 192.0.2.1
34
61
  ```
35
62
 
36
- ### EXAMPLES
63
+ Invalid records throw immediately:
37
64
 
38
65
  ```js
39
- const exampleRRs = {
40
- A: {
41
- owner : 'test.example.com.',
42
- type : 'A',
43
- address: '192.0.2.127',
44
- ttl : 3600,
45
- },
46
- AAAA: {
47
- owner : 'test.example.com.',
48
- type : 'AAAA',
49
- address: '2605:7900:20:a::4',
50
- ttl : 3600,
51
- },
52
- SOA: {
53
- owner : 'example.com.',
54
- type : 'SOA',
55
- mname : 'matt.example.com.',
56
- rname : 'ns1.example.com.',
57
- serial : 1,
58
- refresh: 7200,
59
- retry : 3600,
60
- expire : 1209600,
61
- minimum: 3600,
62
- ttl : 3600,
63
- }
64
- }
65
66
  try {
66
- console.log(new RR.SOA(exampleRRs.SOA))
67
- SOA(11) [Map] {
68
- 'owner' => 'example.com.',
69
- 'ttl' => 3600,
70
- 'class' => 'IN',
71
- 'type' => 'SOA',
72
- 'mname' => 'matt.example.com.',
73
- 'rname' => 'ns1.example.com.',
74
- 'serial' => 1,
75
- 'refresh' => 7200,
76
- 'retry' => 3600,
77
- 'expire' => 1209600,
78
- 'minimum' => 3600
79
- }
80
- }
81
- catch (e) {
82
- console.error(e.message) // invalid RRs throw
67
+ new RR.A({ owner: 'example.com.', address: 'not-an-ip' })
68
+ } catch (err) {
69
+ console.error(err.message) // Error: A address must be IPv4
83
70
  }
84
71
  ```
85
72
 
86
- Validate records by passing a properly formatted JS object to the record-specific class. To validate an A record:
73
+ This library enforces RFC-compliance during construction, catching errors early.
74
+
75
+ ---
76
+
77
+ ## API Reference
78
+
79
+ ### Understanding Record Structure
80
+
81
+ Every DNS record has these standard fields:
82
+
83
+ - **owner** — The domain name this record belongs to (always fully qualified, e.g., `example.com.`)
84
+ - **type** — The record type (A, AAAA, MX, TXT, etc.)
85
+ - **ttl** — Time to live in seconds
86
+ - **class** — Almost always `IN` (Internet); omitted in examples
87
+
88
+ Plus **rdata fields** specific to each record type (e.g., `address` for A records, `preference`/`exchange` for MX records).
89
+
90
+ ### Core Workflows
91
+
92
+ #### 1. **Validate & Create** — Use the Constructor
93
+
94
+ When you have data in JavaScript object form:
87
95
 
88
96
  ```js
89
- const validatedA = new RR.A(exampleRRs.A)
97
+ new RR.SOA({
98
+ owner: 'example.com.',
99
+ mname: 'ns1.example.com.',
100
+ rname: 'hostmaster.example.com.',
101
+ serial: 2024042201,
102
+ refresh: 7200,
103
+ retry: 3600,
104
+ expire: 1209600,
105
+ minimum: 3600,
106
+ ttl: 3600,
107
+ })
90
108
  ```
91
109
 
92
- Manipulate the validated record using pattern named setters:
110
+ **When to use:** Building records programmatically, validating user input, working with API responses.
111
+
112
+ ---
113
+
114
+ #### 2. **Parse BIND Format** — Use `fromBind()`
115
+
116
+ When you have a line from a BIND zone file:
93
117
 
94
118
  ```js
95
- console.log(validatedA.toBind())
96
- test.example.com. 3600 IN A 192.0.2.127
119
+ const rr = RR.A.fromBind('www.example.com. 3600 IN A 192.0.2.1\n')
120
+ console.log(rr.get('address')) // '192.0.2.1'
121
+ ```
122
+
123
+ **When to use:** Processing BIND zone files, DNS configs, or standard zone file exports.
124
+
125
+ ---
126
+
127
+ #### 3. **Parse Tinydns Format** — Use `fromTinydns()`
128
+
129
+ When you have a line from a tinydns data file:
130
+
131
+ ```js
132
+ const rr = RR.A.fromTinydns('+www.example.com:192.0.2.1:3600::\n')
133
+ console.log(rr.get('address')) // '192.0.2.1'
134
+ ```
135
+
136
+ **When to use:** Working with djbdns/tinydns configurations, or when parsing tinydns data files.
137
+
138
+ ---
139
+
140
+ #### 4. **Export to BIND** — Use `toBind()`
141
+
142
+ Convert any validated record to BIND zone file format:
143
+
144
+ ```js
145
+ new RR.MX({
146
+ owner: 'example.com.',
147
+ preference: 10,
148
+ exchange: 'mail.example.com.',
149
+ ttl: 3600,
150
+ }).toBind()
151
+ // example.com 3600 IN MX 10 mail.example.com.
152
+ ```
153
+
154
+ **When to use:** Generating zone files, displaying records for editing, exporting to BIND nameservers.
155
+
156
+ ---
157
+
158
+ #### 5. **Export to Tinydns** — Use `toTinydns()`
159
+
160
+ Convert to tinydns data file format:
161
+
162
+ ```js
163
+ new RR.A({
164
+ owner: 'example.com.',
165
+ address: '192.0.2.1',
166
+ ttl: 3600,
167
+ }).toTinydns()
168
+ // +example.com:192.0.2.1:3600::
169
+ ```
170
+
171
+ **When to use:** Generating tinydns data files, migrating to djbdns, or integrating with tinydns tooling.
172
+
173
+ ---
97
174
 
98
- validatedA.setAddress('192.0.2.128')
99
- console.log(validatedA.toBind())
100
- test.example.com. 3600 IN A 192.0.2.128
175
+ #### 6. **Round-Trip Conversion**
176
+
177
+ Parse from one format, export to another:
178
+
179
+ ```js
180
+ // tinydns → BIND
181
+ const fromTiny = RR.CAA.fromTinydns(
182
+ ':ns1.example.com:257:\\000\\005issue"http\\072\\057\\057letsencrypt.org":3600::\n',
183
+ )
184
+ console.log(fromTiny.toBind())
185
+ // ns1.example.com 3600 IN CAA 0 issue "http://letsencrypt.org"
101
186
  ```
102
187
 
103
- The setters are named: `set` + `Field`, where field is the resource record field name to modify. Multi-word names are camel cased, so a field named `Certificate Usage` has a setter named `setCertificateUsage`. The RFCs aren't always consistent regarding RR field names so aliases are permissible for interoperability.
188
+ **When to use:** DNS migrations, format conversions, tool interoperability.
189
+
190
+ ---
104
191
 
105
- ## FUNCTIONS
192
+ ### Manipulating Records
106
193
 
107
- Get the field names for each RR type with `getFields()`:
194
+ Use **setter methods** to modify validated records. Setter names follow the pattern `set` + `FieldName` (camelCased):
108
195
 
109
196
  ```js
110
- > import * as RR from 'dns-resource-record'
111
- > new RR.A(null).getFields()
112
- [ 'owner', 'ttl', 'class', 'type', 'address' ]
197
+ const a = new RR.A({
198
+ owner: 'example.com.',
199
+ address: '192.0.2.1',
200
+ ttl: 3600,
201
+ })
113
202
 
114
- > new RR.PTR(null).getFields()
115
- [ 'owner', 'ttl', 'class', 'type', 'dname' ]
203
+ a.setAddress('192.0.2.2')
204
+ a.setTtl(7200)
116
205
 
117
- > new RR.SSHFP(null).getFields()
118
- [ 'owner', 'ttl', 'class', 'type', 'algorithm', 'fptype', 'fingerprint' ]
206
+ console.log(a.toBind())
207
+ // example.com 7200 IN A 192.0.2.2
119
208
  ```
120
209
 
121
- Get a list of RFCs for references about each RR type:
210
+ Setters include validation. Invalid values throw with helpful error messages.
211
+
212
+ For a list of available setters, check `getFields('rdata')` for your record type:
122
213
 
123
214
  ```js
124
- > new RR.A(null).getRFCs()
125
- [ 1035 ]
215
+ new RR.SSHFP(null).getFields('rdata')
216
+ // ['algorithm', 'fptype', 'fingerprint']
217
+ // So use: setSshfp(), setFptype(), setFingerprint()
218
+ ```
219
+
220
+ ---
126
221
 
127
- > new RR.SRV(null).getRFCs()
128
- [ 2782 ]
222
+ ### Metadata Methods
129
223
 
130
- > new RR.MX(null).getRFCs()
131
- [ 1035, 2181, 7505 ]
224
+ Get information about record types:
225
+
226
+ #### `getFields([section])`
227
+
228
+ Get field names for a record type. Pass `'rdata'` to get only the custom fields:
229
+
230
+ ```js
231
+ new RR.A(null).getFields() // ['owner', 'ttl', 'class', 'type', 'address']
232
+ new RR.A(null).getFields('rdata') // ['address']
233
+ new RR.MX(null).getFields('rdata') // ['preference', 'exchange']
132
234
  ```
133
235
 
134
- ### toBind
236
+ #### `getRFCs()`
135
237
 
136
- Validate a record and export to BIND format.
238
+ Get RFC references for a record type:
137
239
 
138
240
  ```js
139
- console.log(new RR.A(exampleRRs.A).toBind())
140
- test.example.com 3600 IN A 192.0.2.127
241
+ new RR.A(null).getRFCs() // [1035]
242
+ new RR.MX(null).getRFCs() // [1035, 2181, 7505]
243
+ new RR.SRV(null).getRFCs() // [2782]
244
+ ```
245
+
246
+ #### `getCanonical()`
141
247
 
142
- console.log(new RR.AAAA(exampleRRs.AAAA).toBind())
143
- test.example.com 3600 IN AAAA 2605:7900:20:a::4
248
+ Get a record with all fields populated with default/canonical values:
249
+
250
+ ```js
251
+ new RR.AAAA(null).getCanonical()
252
+ // {
253
+ // owner: 'host.example.com.',
254
+ // address: '2001:0db8:0020:000a:0000:0000:0000:0004',
255
+ // class: 'IN',
256
+ // ttl: 3600,
257
+ // type: 'AAAA'
258
+ // }
144
259
  ```
145
260
 
146
- ### toTinydns
261
+ #### `toJSON()` / `JSON.stringify()`
147
262
 
148
- Validate a record and export to tinydns format:
263
+ Serialize a record to a plain object:
149
264
 
150
265
  ```js
151
- console.log(new RR.A(exampleRRs.A).toTinydns())
152
- +test.example.com:192.0.2.127:3600::
266
+ const a = new RR.A({ owner: 'example.com.', address: '192.0.2.1', ttl: 3600 })
267
+ JSON.stringify(a)
268
+ // {"owner":"example.com.","ttl":3600,"class":"IN","type":"A","address":"192.0.2.1"}
153
269
  ```
154
270
 
155
- ### fromTinydns toBind
271
+ ---
272
+
273
+ ### Advanced: Bypassing Validation
156
274
 
157
- Convert a tinydns line to BIND:
275
+ The `set()` method bypasses validation (use carefully):
158
276
 
159
277
  ```js
160
- console.log(new RR.CAA({
161
- tinyline: ':ns1.example.com:257:\\000\\005issue"http\\072\\057\\057letsencrypt.org":3600::\n'
162
- }).toBind())
163
- ns1.example.com 3600 IN CAA 0 issue "http://letsencrypt.org"
278
+ record.set('address', 'invalid-value')
279
+ // Works, but now the record is malformed — useful only for testing or low-level manipulation
280
+ ```
281
+
282
+ **Note:** Validation is there to protect data integrity. Use at your own risk.
283
+
284
+ ---
285
+
286
+ ## Browser & CDN
287
+
288
+ Use this module directly in browsers via CDN:
289
+
290
+ ```html
291
+ <!DOCTYPE html>
292
+ <html>
293
+ <head>
294
+ <title>DNS Record Validator</title>
295
+ </head>
296
+ <body>
297
+ <h1>DNS Record Validator</h1>
298
+ <pre id="output"></pre>
299
+
300
+ <script type="module">
301
+ // Import from unpkg (or jsdelivr, esm.sh)
302
+ import * as RR from 'https://unpkg.com/@nictool/dns-resource-record@latest/dist/dns-rr.min.js'
303
+
304
+ // Use just like Node.js
305
+ const record = new RR.A({
306
+ owner: 'example.com.',
307
+ address: '192.0.2.1',
308
+ ttl: 3600,
309
+ })
310
+
311
+ document.getElementById('output').textContent = record.toBind()
312
+ </script>
313
+ </body>
314
+ </html>
164
315
  ```
165
316
 
166
- ### set
317
+ **Available CDNs:**
167
318
 
168
- The DNS validation checks can be bypassed entirely by using 'set':
319
+ - **unpkg:** `https://unpkg.com/@nictool/dns-resource-record/dist/dns-rr.min.js`
320
+ - **jsdelivr:** `https://cdn.jsdelivr.net/npm/@nictool/dns-resource-record/dist/dns-rr.min.js`
321
+ - **esm.sh:** `https://esm.sh/@nictool/dns-resource-record`
322
+
323
+ **Live example:** See [nictool.github.io/builder/](https://nictool.github.io/builder/) for an interactive DNS record editor using this library.
324
+
325
+ ---
326
+
327
+ ## Important Concepts
328
+
329
+ ### Domain Name Normalization
330
+
331
+ Domain owner names are:
332
+
333
+ - **Stored fully qualified** (absolute), e.g., `example.com.` not `example.com`
334
+ - **Normalized to lowercase** because:
335
+ - DNS is case-insensitive (RFC 4343, RFC 1035)
336
+ - This library enforces automatic duplicate suppression
337
+ - DNSSEC canonicalization requires it (RFC 4034)
338
+ - Wire format for most RRs requires lowercase
339
+
340
+ **Example:**
169
341
 
170
342
  ```js
171
- > validatedA.set('address', 'oops')
172
- A(5) [Map] {
173
- 'owner' => 'test.example.com',
174
- 'ttl' => 3600,
175
- 'class' => 'IN',
176
- 'type' => 'A',
177
- 'address' => 'oops'
178
- }
343
+ new RR.A({ owner: 'EXAMPLE.COM', address: '192.0.2.1', ttl: 3600 })
344
+ // Automatically normalized to: 'example.com.'
179
345
  ```
180
346
 
181
- Consider this a "running with scissors" mode.
347
+ ### Relative vs Absolute Names
182
348
 
183
- ## Supported Records
349
+ Master zone file expansions (relative domain names) are handled by [dns-zone](https://github.com/NicTool/dns-zone). This library works only with fully qualified names.
350
+
351
+ ### Export Options
352
+
353
+ The `toBind()` and `toMaraDNS()` methods accept an options object to customize output:
354
+
355
+ ```js
356
+ record.toBind({ suppressTtl: true, suppressClass: true, relativeName: true })
357
+ ```
358
+
359
+ See [dns-zone](https://github.com/NicTool/dns-zone) for full options documentation.
360
+
361
+ ## Development
362
+
363
+ No external dependencies. Runs on node.js and modern browsers.
364
+
365
+ **Key scripts:**
366
+
367
+ - `npm test` — Run all tests with node's built-in test runner
368
+ - `npm run watch` — Run tests in watch mode during development
369
+ - `npm run lint` — Check code with ESLint
370
+ - `npm run format` — Auto-format with Prettier and fix linting issues
371
+ - `npm run build` — Regenerate browser bundle and README
372
+ - `npm run test:coverage` — Generate test coverage report
373
+
374
+ **Architecture:**
375
+
376
+ - **rr.js** — Base class with shared DNS logic and validation
377
+ - **rr/\*.js** — Individual RR type implementations
378
+ - **test/\*.js** — Comprehensive test suite for each RR type
379
+
380
+ ## References
381
+
382
+ - [DNS Record Types (Wikipedia)](https://en.wikipedia.org/wiki/List_of_DNS_record_types)
383
+ - [DNS Terminology (NicTool Dictionary)](https://nictool.github.io/Dictionary)
384
+ - [dns-zone](https://www.npmjs.com/package/@nictool/dns-zone) — Zone file operations
385
+ - [dns-nameserver](https://www.npmjs.com/package/@nictool/dns-nameserver) — Nameserver management
386
+
387
+ ---
184
388
 
185
- This module intends to support all current (ie, not officially deprecated) DNS RRs **and** all RRs that are in active use on the internet.
186
-
187
- PRs are welcome, especially PRs with tests.
188
-
189
- | **RR** | **BIND / RFC 1035** | **Tinydns** |
190
- | :------------: | :-----------------: | :----------------: |
191
- | _Common_ |
192
- | **A** | :white_check_mark: | :white_check_mark: |
193
- | **AAAA** | :white_check_mark: | :white_check_mark: |
194
- | **CNAME** | :white_check_mark: | :white_check_mark: |
195
- | **HTTPS** | :white_check_mark: | :white_check_mark: |
196
- | **MX** | :white_check_mark: | :white_check_mark: |
197
- | **NS** | :white_check_mark: | :white_check_mark: |
198
- | **PTR** | :white_check_mark: | :white_check_mark: |
199
- | **SRV** | :white_check_mark: | :white_check_mark: |
200
- | **TXT** | :white_check_mark: | :white_check_mark: |
201
- | _Less Common_ |
202
- | **APL** | :white_check_mark: | :white_check_mark: |
203
- | **CERT** | :white_check_mark: | :white_check_mark: |
204
- | **DHCID** | :white_check_mark: | :white_check_mark: |
205
- | **DNAME** | :white_check_mark: | :white_check_mark: |
206
- | **HIP** | :white_check_mark: | :white_check_mark: |
207
- | **KEY** | :white_check_mark: | :white_check_mark: |
208
- | **KX** | :white_check_mark: | :white_check_mark: |
209
- | **LOC** | :white_check_mark: | :white_check_mark: |
210
- | **NAPTR** | :white_check_mark: | :white_check_mark: |
211
- | **SOA** | :white_check_mark: | :white_check_mark: |
212
- | **SVCB** | :white_check_mark: | :white_check_mark: |
213
- | **TSIG** | :white_check_mark: | :white_check_mark: |
214
- | **URI** | :white_check_mark: | :white_check_mark: |
215
- | _Security_ |
216
- | **CAA** | :white_check_mark: | :white_check_mark: |
217
- | **IPSECKEY** | :white_check_mark: | :white_check_mark: |
218
- | **OPENPGPKEY** | :white_check_mark: | :white_check_mark: |
219
- | **SMIMEA** | :white_check_mark: | :white_check_mark: |
220
- | **SSHFP** | :white_check_mark: | :white_check_mark: |
221
- | **TLSA** | :white_check_mark: | :white_check_mark: |
222
- | _DNSSEC_ |
223
- | **DNSKEY** | :white_check_mark: | :white_check_mark: |
224
- | **DS** | :white_check_mark: | :white_check_mark: |
225
- | **NSEC** | :white_check_mark: | :white_check_mark: |
226
- | **NSEC3** | :white_check_mark: | :white_check_mark: |
227
- | **NSEC3PARAM** | :white_check_mark: | :white_check_mark: |
228
- | **RRSIG** | :white_check_mark: | :white_check_mark: |
229
- | _Deprecated_ |
230
- | **NXT** | :white_check_mark: | :white_check_mark: |
231
- | **SPF** | :white_check_mark: | :white_check_mark: |
232
- | _Obsolete_ |
233
- | **HINFO** | :white_check_mark: | :white_check_mark: |
234
- | **RP** | :white_check_mark: | :white_check_mark: |
235
- | **SIG** | :white_check_mark: | :white_check_mark: |
236
- | **WKS** | :white_check_mark: | :white_check_mark: |
237
-
238
- ## TIPS
239
-
240
- - Domain owner names are:
241
- - stored fully qualified, aka absolute.
242
- - normalized to lower case, because:
243
- - DNS is case insensitive (see RFCs 4343, 1035, 1034)
244
- - this library enforces duplicate suppression
245
- - DNSSEC canonicalization (see RFC 4034)
246
- - wire format for most RRs require it
247
- - Master Zone File expansions exist in [dns-zone](https://github.com/NicTool/dns-zone)
248
- - to{Bind|MaraDNS} output can be influenced (suppress TTL, class, relative domain names) with an options object. See it in `bin/dns-zone` in the [dns-zone](https://github.com/NicTool/dns-zone) package.
249
-
250
- ## SEE ALSO
251
-
252
- - [Dictionary of DNS terms](https://nictool.github.io/web/Dictionary)
253
- - [Wikipedia, List of DNS Record Types](https://en.wikipedia.org/wiki/List_of_DNS_record_types)
254
- - @nictool/[dns-zone](https://www.npmjs.com/package/@nictool/dns-zone)
255
- - @nictool/[dns-nameserver](https://www.npmjs.com/package/@nictool/dns-nameserver)
256
-
257
- ## TODO
258
-
259
- - [ ] export a web page for each RR type
260
-
261
- ## DEVELOP
262
-
263
- - There are no dependencies. That's no accident.
264
- - ES modules for use by node.js and browser
265
- - Platform independence is a goal
266
- - [x] CI tests are on linux, windows, and macos
389
+ [ci-img]: https://github.com/NicTool/dns-resource-record/actions/workflows/ci.yml/badge.svg
390
+ [ci-url]: https://github.com/NicTool/dns-resource-record/actions/workflows/ci.yml
391
+ [cov-img]: https://coveralls.io/repos/github/NicTool/dns-resource-record/badge.svg
392
+ [cov-url]: https://coveralls.io/github/NicTool/dns-resource-record
393
+ [bind-url]: https://www.isc.org/bind/
394
+ [knot-url]: https://www.knot-dns.cz
395
+ [nsd-url]: https://www.nlnetlabs.nl/projects/nsd/about/
396
+ [pdns-url]: https://www.powerdns.com/powerdns-authoritative-server