@sdxc/zone-file 0.0.0-stage → 2026.10.9

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,218 @@
1
+ /**
2
+ * The types of a master file: the typed data of each record type, the record a zone file
3
+ * declares with its position in the file, the entries it could not use, and the options
4
+ * that steer reading and writing. The entry point exports them both top-level and as `ZoneFile`.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
9
+ /** The record types whose data is read into typed fields. */
10
+ export type TypedRecordType = "A" | "AAAA" | "CNAME" | "NS" | "PTR" | "DNAME" | "MX" | "TXT" | "CAA" | "SRV" | "SOA";
11
+ /** A record type by mnemonic; the typed ones autocomplete, any other name is accepted. */
12
+ export type RecordType = TypedRecordType | (string & {});
13
+ /** A record class; `IN` is the internet, `CLASSnnn` spells one without a mnemonic. */
14
+ export type RecordClass = "IN" | "CH" | "HS" | "CS" | (string & {});
15
+ /** An IPv4 address, in dotted-quad form. */
16
+ export interface AData {
17
+ type: "A";
18
+ address: string;
19
+ }
20
+ /** An IPv6 address. */
21
+ export interface AAAAData {
22
+ type: "AAAA";
23
+ /** In RFC 5952 canonical form: lowercase, zero runs compressed. */
24
+ address: string;
25
+ }
26
+ /** An alias: the owner resolves as `target` does. */
27
+ export interface CNAMEData {
28
+ type: "CNAME";
29
+ target: string;
30
+ }
31
+ /** A name server authoritative for the zone at the owner. */
32
+ export interface NSData {
33
+ type: "NS";
34
+ host: string;
35
+ }
36
+ /** A pointer to another name, the reading of a reverse-lookup (`in-addr.arpa`) owner. */
37
+ export interface PTRData {
38
+ type: "PTR";
39
+ target: string;
40
+ }
41
+ /** An alias for every name below the owner (RFC 6672), the owner itself excluded. */
42
+ export interface DNAMEData {
43
+ type: "DNAME";
44
+ target: string;
45
+ }
46
+ /** A mail exchanger; lower `preference` values are tried first. */
47
+ export interface MXData {
48
+ type: "MX";
49
+ preference: number;
50
+ /** The mail host; `"."` is an RFC 7505 null MX, a domain that accepts no mail. */
51
+ exchange: string;
52
+ }
53
+ /** Free text, such as SPF policies, DKIM keys and verification tokens. */
54
+ export interface TXTData {
55
+ type: "TXT";
56
+ /** The character-strings concatenated with nothing between them, as SPF and DKIM read it. */
57
+ text: string;
58
+ /** The character-strings as published, for the rare record whose boundaries matter. */
59
+ strings: string[];
60
+ }
61
+ /** Which certificate authorities may issue for the name (RFC 8659). */
62
+ export interface CAAData {
63
+ type: "CAA";
64
+ /** The flags octet as published, reserved bits included, so the record prints back unchanged. */
65
+ flags: number;
66
+ /** Bit 128 of `flags`: a CA that does not understand `tag` must refuse to issue. */
67
+ critical: boolean;
68
+ /** Lowercased, since tags match case-insensitively. */
69
+ tag: string;
70
+ value: string;
71
+ }
72
+ /** Where a service runs; lower `priority` first, `weight` spreads load within one priority. */
73
+ export interface SRVData {
74
+ type: "SRV";
75
+ priority: number;
76
+ weight: number;
77
+ port: number;
78
+ target: string;
79
+ }
80
+ /** The zone's start of authority, found at its apex and in negative answers. */
81
+ export interface SOAData {
82
+ type: "SOA";
83
+ primary: string;
84
+ /** The responsible mailbox in DNS form: its first label is the local part. */
85
+ mailbox: string;
86
+ serial: number;
87
+ refresh: number;
88
+ retry: number;
89
+ expire: number;
90
+ /** Bounds how long a negative answer may be cached (RFC 2308). */
91
+ minimum: number;
92
+ }
93
+ /** Data of a type without a typed reading, kept as written. */
94
+ export interface UnknownData {
95
+ type: string;
96
+ data: string;
97
+ }
98
+ /** A record's type-specific fields, what `parseRecordData` reads out of RDATA. */
99
+ export type RecordData<Type extends RecordType> = Type extends "A" ? AData : Type extends "AAAA" ? AAAAData : Type extends "CNAME" ? CNAMEData : Type extends "NS" ? NSData : Type extends "PTR" ? PTRData : Type extends "DNAME" ? DNAMEData : Type extends "MX" ? MXData : Type extends "TXT" ? TXTData : Type extends "CAA" ? CAAData : Type extends "SRV" ? SRVData : Type extends "SOA" ? SOAData : UnknownData;
100
+ /** What every record read from a file carries beside its data. */
101
+ export interface RecordFields {
102
+ /** Absolute, lowercased, no trailing dot; the root is `"."`. */
103
+ name: string;
104
+ /** Seconds; `null` when nothing in the file or the options stated one. */
105
+ ttl: number | null;
106
+ class: RecordClass;
107
+ /** The included file the record came from; `null` for the text passed to `parse`. */
108
+ file: string | null;
109
+ /** 1-based line the entry starts on. */
110
+ line: number;
111
+ /** The line a parenthesized entry ends on; `line` for a one-line entry. */
112
+ endLine: number;
113
+ /** The `;` comment that ends the entry, trimmed; `null` without one. */
114
+ comment: string | null;
115
+ }
116
+ /**
117
+ * A record of an untyped type. Its data is kept as written, so relative names inside it
118
+ * mean something only under the `origin` it was read with.
119
+ */
120
+ export interface UntypedRecord extends UnknownData, RecordFields {
121
+ origin: string;
122
+ }
123
+ /** The record a zone file declares for `Type`. */
124
+ export type RecordFor<Type extends RecordType> = Type extends TypedRecordType ? RecordData<Type> & RecordFields : UntypedRecord;
125
+ /** Any record a zone file declares. */
126
+ export type Record = {
127
+ [Type in TypedRecordType]: RecordFor<Type>;
128
+ }[TypedRecordType] | UntypedRecord;
129
+ /** Why an entry did not become a record. */
130
+ export type RejectionReason =
131
+ /** An unterminated quote, unbalanced parentheses, a bad name or TTL, a missing type or RDATA. */
132
+ "malformed"
133
+ /** RDATA that does not fit its type's typed reading. */
134
+ | "invalid-data"
135
+ /** A blank owner with no earlier record to take it from. */
136
+ | "missing-owner"
137
+ /** `$INCLUDE` without an `include` option, a file it returned `null` for, or nesting past 8. */
138
+ | "include"
139
+ /** `$GENERATE`, or any other `$` word. */
140
+ | "unsupported-directive";
141
+ /** An entry that did not become a record. */
142
+ export interface Rejection {
143
+ file: string | null;
144
+ line: number;
145
+ endLine: number;
146
+ /** The entry as written, every line of it. */
147
+ input: string;
148
+ reason: RejectionReason;
149
+ /** The detail a log needs, such as the RDATA error. */
150
+ message: string;
151
+ }
152
+ /** What a zone file amounts to: the records it declares and the entries it could not use. */
153
+ export interface Zone {
154
+ /** The origin at the end of the file, after any `$ORIGIN`. */
155
+ origin: string;
156
+ records: Record[];
157
+ rejected: Rejection[];
158
+ }
159
+ /** Options for `parse`. */
160
+ export interface ParseOptions {
161
+ /** The initial `$ORIGIN`; `@` and relative names resolve against it until a `$ORIGIN` line changes it. */
162
+ origin: string;
163
+ /**
164
+ * The TTL a record gets when neither it, a `$TTL` nor an earlier record states one.
165
+ *
166
+ * @default null
167
+ */
168
+ ttl?: number | null;
169
+ /** The text of an `$INCLUDE`d file, `null` when it is unavailable; without it every `$INCLUDE` is rejected. */
170
+ include?: (fileName: string, origin: string) => string | null;
171
+ /**
172
+ * `"origin-suffix"` also reads a dotless name that equals the origin or ends in it as
173
+ * absolute, for exports that drop the trailing dot on fully-qualified names.
174
+ *
175
+ * @default "rfc1035"
176
+ */
177
+ relativeNames?: "rfc1035" | "origin-suffix";
178
+ /**
179
+ * The largest input in UTF-8 bytes, counted across included files.
180
+ *
181
+ * @default 1048576
182
+ */
183
+ maxBytes?: number;
184
+ }
185
+ /** What a record to write needs beside its data; everything a parsed record has is accepted. */
186
+ export interface RecordInputFields {
187
+ /** Absolute, with or without the trailing dot. */
188
+ name: string;
189
+ /** Left out of the line when `null`, absent, or equal to the zone's `ttl`. */
190
+ ttl?: number | null;
191
+ /** @default "IN" */
192
+ class?: RecordClass;
193
+ comment?: string | null;
194
+ }
195
+ /** A record to write: typed data, or untyped data with the origin its relative names need. */
196
+ export type RecordInput = {
197
+ [Type in TypedRecordType]: RecordData<Type> & RecordInputFields;
198
+ }[TypedRecordType] | (UnknownData & RecordInputFields & {
199
+ origin?: string;
200
+ });
201
+ /** A zone to write; a `Zone` from `parse` is one. */
202
+ export interface ZoneInput {
203
+ /** Written as `$ORIGIN`, and the name `relative` output is relative to. */
204
+ origin?: string;
205
+ /** Written as `$TTL`. */
206
+ ttl?: number | null;
207
+ records: readonly RecordInput[];
208
+ }
209
+ /** Options for `stringify`. */
210
+ export interface StringifyOptions {
211
+ /**
212
+ * Writes names under the origin relative to it and the apex as `@`, the form people keep
213
+ * in git; every other name is written absolute.
214
+ *
215
+ * @default false
216
+ */
217
+ relative?: boolean;
218
+ }
package/dist/types.js ADDED
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The types of a master file: the typed data of each record type, the record a zone file
3
+ * declares with its position in the file, the entries it could not use, and the options
4
+ * that steer reading and writing. The entry point exports them both top-level and as `ZoneFile`.
5
+ *
6
+ * @author [Sergio Xalambrí](https://sergiodxa.com)
7
+ * @copyright Sergio Xalambrí 2026
8
+ */
package/package.json CHANGED
@@ -1,6 +1,31 @@
1
1
  {
2
- "name": "@sdxc/zone-file",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "@sdxc/zone-file",
3
+ "version": "2026.10.9",
4
+ "description": "Read and write RFC 1035 DNS zone files, with the record data codec for every typed record",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "exports": {
8
+ ".": "./dist/index.js"
9
+ },
10
+ "dependencies": {
11
+ "@sdxc/result": "2026.10.6"
12
+ },
13
+ "gitHead": "64fa732ed0a8ca8693a35aeef6345ae5be2534ef",
14
+ "publishConfig": {
15
+ "access": "public"
16
+ },
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "git+https://github.com/sergiodxa/monorepo.git",
20
+ "directory": "packages/zone-file"
21
+ },
22
+ "homepage": "https://sdxc.sergiodxa.com/api/zone-file",
23
+ "author": {
24
+ "name": "Sergio Xalambrí",
25
+ "url": "https://sergiodxa.com"
26
+ },
27
+ "funding": {
28
+ "type": "github",
29
+ "url": "https://github.com/sponsors/sergiodxa"
30
+ }
31
+ }