ip-utilities 1.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.
Files changed (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +238 -0
  3. package/dist/cidr.d.ts +2 -0
  4. package/dist/cidr.d.ts.map +1 -0
  5. package/dist/cidr.js +1 -0
  6. package/dist/index.d.ts +54 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +89 -0
  9. package/dist/internal/cidr.d.ts +112 -0
  10. package/dist/internal/cidr.d.ts.map +1 -0
  11. package/dist/internal/cidr.js +297 -0
  12. package/dist/internal/ipv4-ranges.d.ts +26 -0
  13. package/dist/internal/ipv4-ranges.d.ts.map +1 -0
  14. package/dist/internal/ipv4-ranges.js +73 -0
  15. package/dist/internal/ipv4.d.ts +44 -0
  16. package/dist/internal/ipv4.d.ts.map +1 -0
  17. package/dist/internal/ipv4.js +183 -0
  18. package/dist/internal/ipv6-ranges.d.ts +47 -0
  19. package/dist/internal/ipv6-ranges.d.ts.map +1 -0
  20. package/dist/internal/ipv6-ranges.js +159 -0
  21. package/dist/internal/ipv6.d.ts +67 -0
  22. package/dist/internal/ipv6.d.ts.map +1 -0
  23. package/dist/internal/ipv6.js +385 -0
  24. package/dist/internal/regex.d.ts +37 -0
  25. package/dist/internal/regex.d.ts.map +1 -0
  26. package/dist/internal/regex.js +118 -0
  27. package/dist/internal/sort.d.ts +22 -0
  28. package/dist/internal/sort.d.ts.map +1 -0
  29. package/dist/internal/sort.js +207 -0
  30. package/dist/ipv4.d.ts +2 -0
  31. package/dist/ipv4.d.ts.map +1 -0
  32. package/dist/ipv4.js +1 -0
  33. package/dist/ipv6.d.ts +2 -0
  34. package/dist/ipv6.d.ts.map +1 -0
  35. package/dist/ipv6.js +1 -0
  36. package/dist/ranges.d.ts +3 -0
  37. package/dist/ranges.d.ts.map +1 -0
  38. package/dist/ranges.js +2 -0
  39. package/dist/regex.d.ts +3 -0
  40. package/dist/regex.d.ts.map +1 -0
  41. package/dist/regex.js +1 -0
  42. package/dist/sort.d.ts +2 -0
  43. package/dist/sort.d.ts.map +1 -0
  44. package/dist/sort.js +1 -0
  45. package/dist/types.d.ts +26 -0
  46. package/dist/types.d.ts.map +1 -0
  47. package/dist/types.js +1 -0
  48. package/package.json +78 -0
@@ -0,0 +1,297 @@
1
+ import { parseIPv4, parseIPv4Raw, maskV4LUT } from "./ipv4.js";
2
+ import { parseIPv6, parseIPv6Raw, ipv6RawBuf } from "./ipv6.js";
3
+ import { matchesCidr, prefixMaskV6 } from "./ipv6-ranges.js";
4
+ // --- Constants & lookup tables ---
5
+ // Prebuilt IPv6 prefix masks for all prefix lengths 0-128, four uint32 words each
6
+ const V6_MASK_LUT = new Uint32Array(129 * 4);
7
+ for (let p = 0; p <= 128; p++) {
8
+ const base = p * 4;
9
+ for (let w = 0; w < 4; w++)
10
+ V6_MASK_LUT[base + w] = prefixMaskV6(p, w);
11
+ }
12
+ // --- Mutable state ---
13
+ // Last parsed IPv4 raw value from parseIPOrCIDR
14
+ export let parseIPOrCIDRv4 = 0;
15
+ // --- Exports: prefix parsing ---
16
+ /**
17
+ * Parses a decimal prefix length from a substring.
18
+ * @param s - Source string
19
+ * @param start - Start index of the prefix digits
20
+ * @param end - End index (exclusive)
21
+ * @param max - Maximum allowed prefix value
22
+ * @returns The prefix length, or -1 if invalid
23
+ */
24
+ export function parsePrefixInline(s, start, end, max) {
25
+ const len = end - start;
26
+ if (len === 0 || len > 3)
27
+ return -1;
28
+ if (len > 1 && s.charCodeAt(start) === 48)
29
+ return -1;
30
+ let v = 0;
31
+ for (let i = start; i < end; i++) {
32
+ const ch = s.charCodeAt(i) - 48;
33
+ if (ch < 0 || ch > 9)
34
+ return -1;
35
+ v = v * 10 + ch;
36
+ }
37
+ return v > max ? -1 : v;
38
+ }
39
+ // --- Exports: CIDR parsing ---
40
+ /**
41
+ * Parses a CIDR string in IPv4 notation (e.g. "192.168.1.0/24").
42
+ * @param s - The CIDR string
43
+ * @returns The parsed CIDRv4, or null if invalid
44
+ */
45
+ export function parseCIDRv4(s) {
46
+ const slashIdx = s.indexOf('/');
47
+ if (slashIdx === -1)
48
+ return null;
49
+ const addr = parseIPv4(s, slashIdx);
50
+ if (addr === null)
51
+ return null;
52
+ const prefix = parsePrefixInline(s, slashIdx + 1, s.length, 32);
53
+ if (prefix === -1)
54
+ return null;
55
+ return { addr, prefix, kind: 4 };
56
+ }
57
+ /**
58
+ * Parses a CIDR string in IPv6 notation (e.g. "::1/128").
59
+ * @param s - The CIDR string
60
+ * @returns The parsed CIDRv6, or null if invalid
61
+ */
62
+ export function parseCIDRv6(s) {
63
+ const slashIdx = s.indexOf('/');
64
+ if (slashIdx === -1)
65
+ return null;
66
+ const addr = parseIPv6(s, slashIdx);
67
+ if (addr === null)
68
+ return null;
69
+ const prefix = parsePrefixInline(s, slashIdx + 1, s.length, 128);
70
+ if (prefix === -1)
71
+ return null;
72
+ return { addr, prefix, kind: 6 };
73
+ }
74
+ /**
75
+ * Parses a CIDR string, auto-detecting IPv4 or IPv6.
76
+ * @param s - The CIDR string
77
+ * @returns The parsed CIDR, or null if invalid
78
+ */
79
+ export function parseCIDR(s) {
80
+ const c0 = s.charCodeAt(0);
81
+ if (c0 >= 48 && c0 <= 57) {
82
+ let hasColon = false;
83
+ for (let i = 1, len = s.length; i < len; i++) {
84
+ const ch = s.charCodeAt(i);
85
+ if (ch === 58) {
86
+ hasColon = true;
87
+ break;
88
+ }
89
+ if (ch === 47)
90
+ break;
91
+ }
92
+ if (!hasColon)
93
+ return parseCIDRv4(s);
94
+ }
95
+ return parseCIDRv6(s);
96
+ }
97
+ // --- Exports: validation ---
98
+ /**
99
+ * Checks whether a string is valid CIDR notation (IPv4 or IPv6).
100
+ * @param s - The string to validate
101
+ * @returns True if the string is valid CIDR
102
+ */
103
+ export function isCIDR(s) {
104
+ const slashIdx = s.indexOf('/');
105
+ if (slashIdx === -1)
106
+ return false;
107
+ const c0 = s.charCodeAt(0);
108
+ if (c0 >= 48 && c0 <= 57) {
109
+ let hasColon = false;
110
+ for (let i = 1; i < slashIdx; i++) {
111
+ if (s.charCodeAt(i) === 58) {
112
+ hasColon = true;
113
+ break;
114
+ }
115
+ }
116
+ if (!hasColon) {
117
+ return parseIPv4Raw(s, 0, slashIdx) !== -1 && parsePrefixInline(s, slashIdx + 1, s.length, 32) !== -1;
118
+ }
119
+ }
120
+ return parseIPv6Raw(s, slashIdx) && parsePrefixInline(s, slashIdx + 1, s.length, 128) !== -1;
121
+ }
122
+ // --- Exports: containment ---
123
+ /**
124
+ * Checks whether an IPv4 address is within a CIDRv4 range.
125
+ * @param ip - The IPv4 address
126
+ * @param cidr - The CIDRv4 range
127
+ * @returns True if the address is within the range
128
+ */
129
+ export function ipInCIDRv4(ip, cidr) {
130
+ const m = maskV4LUT[cidr.prefix];
131
+ return ((ip.ip & m) >>> 0) === ((cidr.addr.ip & m) >>> 0);
132
+ }
133
+ /**
134
+ * Checks whether an IPv6 address is within a CIDRv6 range.
135
+ * @param ip - The IPv6 address
136
+ * @param cidr - The CIDRv6 range
137
+ * @returns True if the address is within the range
138
+ */
139
+ export function ipInCIDRv6(ip, cidr) {
140
+ return matchesCidr(ip.w0, ip.w1, ip.w2, ip.w3, cidr.addr.w0, cidr.addr.w1, cidr.addr.w2, cidr.addr.w3, cidr.prefix);
141
+ }
142
+ /**
143
+ * Checks whether an IP address is within a CIDR range. Both must be the same version.
144
+ * @param ip - The IP address (IPv4 or IPv6)
145
+ * @param cidr - The CIDR range (IPv4 or IPv6)
146
+ * @returns True if the address is within the range, false if mismatched versions
147
+ */
148
+ export function ipInCIDR(ip, cidr) {
149
+ if (ip.kind === 4 && cidr.kind === 4)
150
+ return ipInCIDRv4(ip, cidr);
151
+ if (ip.kind === 6 && cidr.kind === 6)
152
+ return ipInCIDRv6(ip, cidr);
153
+ return false;
154
+ }
155
+ /**
156
+ * Parses an IP string and CIDR string, then checks containment.
157
+ * @param ipStr - The IP address string
158
+ * @param cidrStr - The CIDR range string
159
+ * @returns True if the IP is within the CIDR range
160
+ */
161
+ export function isIPInCIDR(ipStr, cidrStr) {
162
+ const cidr = parseCIDR(cidrStr);
163
+ if (cidr === null)
164
+ return false;
165
+ if (cidr.kind === 4) {
166
+ const ip = parseIPv4(ipStr);
167
+ if (ip === null)
168
+ return false;
169
+ return ipInCIDRv4(ip, cidr);
170
+ }
171
+ const ip = parseIPv6(ipStr);
172
+ if (ip === null)
173
+ return false;
174
+ return ipInCIDRv6(ip, cidr);
175
+ }
176
+ // --- Exports: network & broadcast ---
177
+ /**
178
+ * Computes the network address (first address) of an IPv4 CIDR range.
179
+ * @param cidr - The CIDRv4 range
180
+ * @returns The network address
181
+ */
182
+ export function networkAddressV4(cidr) {
183
+ const m = maskV4LUT[cidr.prefix];
184
+ return { ip: (cidr.addr.ip & m) >>> 0, kind: 4 };
185
+ }
186
+ /**
187
+ * Computes the broadcast address (last address) of an IPv4 CIDR range.
188
+ * @param cidr - The CIDRv4 range
189
+ * @returns The broadcast address
190
+ */
191
+ export function broadcastAddressV4(cidr) {
192
+ const m = maskV4LUT[cidr.prefix];
193
+ return { ip: (cidr.addr.ip | ~m) >>> 0, kind: 4 };
194
+ }
195
+ /**
196
+ * Computes the network address (first address) of an IPv6 CIDR range.
197
+ * @param cidr - The CIDRv6 range
198
+ * @returns The network address
199
+ */
200
+ export function networkAddressV6(cidr) {
201
+ const base = cidr.prefix << 2;
202
+ const a = cidr.addr;
203
+ return {
204
+ w0: (a.w0 & V6_MASK_LUT[base]) >>> 0,
205
+ w1: (a.w1 & V6_MASK_LUT[base + 1]) >>> 0,
206
+ w2: (a.w2 & V6_MASK_LUT[base + 2]) >>> 0,
207
+ w3: (a.w3 & V6_MASK_LUT[base + 3]) >>> 0,
208
+ kind: 6,
209
+ };
210
+ }
211
+ /**
212
+ * Computes the broadcast address (last address) of an IPv6 CIDR range.
213
+ * @param cidr - The CIDRv6 range
214
+ * @returns The broadcast address
215
+ */
216
+ export function broadcastAddressV6(cidr) {
217
+ const base = cidr.prefix << 2;
218
+ const a = cidr.addr;
219
+ return {
220
+ w0: (a.w0 | ~V6_MASK_LUT[base]) >>> 0,
221
+ w1: (a.w1 | ~V6_MASK_LUT[base + 1]) >>> 0,
222
+ w2: (a.w2 | ~V6_MASK_LUT[base + 2]) >>> 0,
223
+ w3: (a.w3 | ~V6_MASK_LUT[base + 3]) >>> 0,
224
+ kind: 6,
225
+ };
226
+ }
227
+ // --- Exports: subnet utilities ---
228
+ /**
229
+ * Returns the subnet mask for an IPv4 prefix length.
230
+ * @param prefix - Prefix length (0-32)
231
+ * @returns The uint32 subnet mask
232
+ */
233
+ export function subnetMaskV4(prefix) {
234
+ return maskV4LUT[prefix];
235
+ }
236
+ /**
237
+ * Converts a subnet mask to its prefix length.
238
+ * @param mask - The uint32 subnet mask (must be contiguous)
239
+ * @returns The prefix length, or null if the mask is not contiguous
240
+ */
241
+ export function prefixFromSubnetMask(mask) {
242
+ if (mask === 0)
243
+ return 0;
244
+ const inv = (~mask) >>> 0;
245
+ if ((inv & (inv + 1)) !== 0)
246
+ return null;
247
+ return Math.clz32(inv);
248
+ }
249
+ // --- Exports: IP/CIDR routing ---
250
+ /**
251
+ * Parses an IP or CIDR string, routing v4/v6 in a single forward scan.
252
+ * On success, the v4 result is in {@link parseIPOrCIDRv4} and v6 result in ipv6RawBuf.
253
+ * @param s - The IP or CIDR string
254
+ * @returns 4 for valid IPv4, 6 for valid IPv6, 0 for invalid
255
+ */
256
+ export function parseIPOrCIDR(s) {
257
+ const len = s.length;
258
+ const c0 = s.charCodeAt(0);
259
+ if (c0 >= 48 && c0 <= 57) {
260
+ let hasColon = false;
261
+ let slashIdx = -1;
262
+ for (let i = 1; i < len; i++) {
263
+ const ch = s.charCodeAt(i);
264
+ if (ch === 58) {
265
+ hasColon = true;
266
+ break;
267
+ }
268
+ if (ch === 47) {
269
+ slashIdx = i;
270
+ break;
271
+ }
272
+ }
273
+ if (!hasColon) {
274
+ if (slashIdx === -1) {
275
+ parseIPOrCIDRv4 = parseIPv4Raw(s, 0, len);
276
+ return parseIPOrCIDRv4 !== -1 ? 4 : 0;
277
+ }
278
+ parseIPOrCIDRv4 = parseIPv4Raw(s, 0, slashIdx);
279
+ if (parseIPOrCIDRv4 === -1 || parsePrefixInline(s, slashIdx + 1, len, 32) === -1)
280
+ return 0;
281
+ return 4;
282
+ }
283
+ }
284
+ const slashIdx = s.indexOf('/');
285
+ if (slashIdx === -1)
286
+ return parseIPv6Raw(s, len) ? 6 : 0;
287
+ if (!parseIPv6Raw(s, slashIdx) || parsePrefixInline(s, slashIdx + 1, len, 128) === -1)
288
+ return 0;
289
+ return 6;
290
+ }
291
+ /**
292
+ * Constructs an IPv6Addr from the shared ipv6RawBuf after a successful parseIPv6Raw call.
293
+ * @returns The IPv6Addr built from the raw buffer
294
+ */
295
+ export function v6AddrFromBuf() {
296
+ return { w0: ipv6RawBuf[0], w1: ipv6RawBuf[1], w2: ipv6RawBuf[2], w3: ipv6RawBuf[3], kind: 6 };
297
+ }
@@ -0,0 +1,26 @@
1
+ import type { IPv4RangeName } from '../types.ts';
2
+ /**
3
+ * Classifies a packed uint32 IPv4 address into its IANA-assigned range.
4
+ * @param ip - Packed uint32 IP address
5
+ * @returns The range name (e.g. "private", "loopback", "unicast")
6
+ */
7
+ export declare function ipv4Range(ip: number): IPv4RangeName;
8
+ /**
9
+ * Checks whether a packed uint32 IPv4 address is in a private range (RFC 1918).
10
+ * @param ip - Packed uint32 IP address
11
+ * @returns True if the address is in 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16
12
+ */
13
+ export declare function isPrivateIPv4(ip: number): boolean;
14
+ /**
15
+ * Checks whether a packed uint32 IPv4 address is a loopback address (127.0.0.0/8).
16
+ * @param ip - Packed uint32 IP address
17
+ * @returns True if the address is in the loopback range
18
+ */
19
+ export declare function isLoopbackIPv4(ip: number): boolean;
20
+ /**
21
+ * Checks whether a packed uint32 IPv4 address is link-local (169.254.0.0/16).
22
+ * @param ip - Packed uint32 IP address
23
+ * @returns True if the address is in the link-local range
24
+ */
25
+ export declare function isLinkLocalIPv4(ip: number): boolean;
26
+ //# sourceMappingURL=ipv4-ranges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipv4-ranges.d.ts","sourceRoot":"","sources":["../../src/internal/ipv4-ranges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAwChD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,aAAa,CAMnD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAMjD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAElD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAEnD"}
@@ -0,0 +1,73 @@
1
+ const RANGE_MASK = new Uint32Array([
2
+ 0xFFFFFFFF, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00,
3
+ 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00, 0xFFFFFF00,
4
+ 0xFFFFFF00, 0xFFFF0000, 0xFFFF0000, 0xFFFE0000,
5
+ 0xFFF00000, 0xFFC00000, 0xFF000000, 0xFF000000,
6
+ 0xFF000000, 0xF0000000, 0xF0000000,
7
+ ]);
8
+ const RANGE_MASKED = new Uint32Array([
9
+ 0xFFFFFFFF, 0xC0AF3000, 0xC01FC400, 0xC034C100,
10
+ 0xC0000000, 0xC0000200, 0xC0586300, 0xC6336400,
11
+ 0xCB007100, 0xC0A80000, 0xA9FE0000, 0xC6120000,
12
+ 0xAC100000, 0x64400000, 0x0A000000, 0x7F000000,
13
+ 0x00000000, 0xE0000000, 0xF0000000,
14
+ ]);
15
+ const RANGE_NAMES = [
16
+ 'broadcast', 'as112', 'as112', 'amt',
17
+ 'reserved', 'reserved', 'reserved', 'reserved',
18
+ 'reserved', 'private', 'linkLocal', 'reserved',
19
+ 'private', 'carrierGradeNat', 'private', 'loopback',
20
+ 'unspecified', 'multicast', 'reserved',
21
+ ];
22
+ const RANGE_COUNT = RANGE_MASK.length;
23
+ // First-octet filter: 0 = may belong to a special range, 0xFF = unicast
24
+ const FIRST_OCTET = new Uint8Array(256);
25
+ FIRST_OCTET.fill(0xFF);
26
+ for (let i = 0; i < RANGE_COUNT; i++) {
27
+ const lo = RANGE_MASKED[i] >>> 24;
28
+ const maskBits = Math.clz32(~RANGE_MASK[i] >>> 0);
29
+ const span = maskBits <= 8 ? 1 << (8 - maskBits) : 1;
30
+ for (let o = lo; o < lo + span && o < 256; o++) {
31
+ FIRST_OCTET[o] = 0;
32
+ }
33
+ }
34
+ /**
35
+ * Classifies a packed uint32 IPv4 address into its IANA-assigned range.
36
+ * @param ip - Packed uint32 IP address
37
+ * @returns The range name (e.g. "private", "loopback", "unicast")
38
+ */
39
+ export function ipv4Range(ip) {
40
+ if (FIRST_OCTET[ip >>> 24] === 0xFF)
41
+ return 'unicast';
42
+ for (let i = 0; i < RANGE_COUNT; i++) {
43
+ if (((ip & RANGE_MASK[i]) >>> 0) === RANGE_MASKED[i])
44
+ return RANGE_NAMES[i];
45
+ }
46
+ return 'unicast';
47
+ }
48
+ /**
49
+ * Checks whether a packed uint32 IPv4 address is in a private range (RFC 1918).
50
+ * @param ip - Packed uint32 IP address
51
+ * @returns True if the address is in 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16
52
+ */
53
+ export function isPrivateIPv4(ip) {
54
+ return ((ip >>> 24) === 10 ||
55
+ (ip >>> 20) === 0xAC1 ||
56
+ (ip >>> 16) === 0xC0A8);
57
+ }
58
+ /**
59
+ * Checks whether a packed uint32 IPv4 address is a loopback address (127.0.0.0/8).
60
+ * @param ip - Packed uint32 IP address
61
+ * @returns True if the address is in the loopback range
62
+ */
63
+ export function isLoopbackIPv4(ip) {
64
+ return (ip >>> 24) === 127;
65
+ }
66
+ /**
67
+ * Checks whether a packed uint32 IPv4 address is link-local (169.254.0.0/16).
68
+ * @param ip - Packed uint32 IP address
69
+ * @returns True if the address is in the link-local range
70
+ */
71
+ export function isLinkLocalIPv4(ip) {
72
+ return (ip >>> 16) === 0xA9FE;
73
+ }
@@ -0,0 +1,44 @@
1
+ import type { IPv4Addr } from '../types.ts';
2
+ declare const maskV4LUT: Uint32Array<ArrayBuffer>;
3
+ export { maskV4LUT };
4
+ /**
5
+ * Parses a strict dotted-decimal IPv4 string into a raw uint32.
6
+ * @param s - Source string
7
+ * @param start - Start index within the string
8
+ * @param end - End index (exclusive) within the string
9
+ * @returns The packed uint32 IP address, or -1 if invalid
10
+ */
11
+ export declare function parseIPv4Raw(s: string, start: number, end: number): number;
12
+ /**
13
+ * Parses a strict dotted-decimal IPv4 string into an IPv4Addr.
14
+ * @param s - The IPv4 string (e.g. "192.168.1.1")
15
+ * @param end - Optional end index for parsing a substring
16
+ * @returns The parsed address, or null if invalid
17
+ */
18
+ export declare function parseIPv4(s: string, end?: number): IPv4Addr | null;
19
+ /**
20
+ * Checks whether a string is a valid strict dotted-decimal IPv4 address.
21
+ * @param s - The string to validate
22
+ * @returns True if the string is a valid IPv4 address
23
+ */
24
+ export declare function isIPv4(s: string): boolean;
25
+ /**
26
+ * Parses an IPv4 string with relaxed rules: hex (0x), octal (0), and
27
+ * classful shorthand (e.g. "10.1" = "10.0.0.1") are accepted.
28
+ * @param s - The IPv4 string in any accepted notation
29
+ * @returns The parsed address, or null if invalid
30
+ */
31
+ export declare function parseIPv4Loose(s: string): IPv4Addr | null;
32
+ /**
33
+ * Extracts the four octets of a packed uint32 IPv4 address.
34
+ * @param ip - Packed uint32 IP address
35
+ * @returns Tuple of four octets [a, b, c, d]
36
+ */
37
+ export declare function ipv4ToOctets(ip: number): [number, number, number, number];
38
+ /**
39
+ * Converts a packed uint32 IPv4 address to dotted-decimal string.
40
+ * @param ip - Packed uint32 IP address
41
+ * @returns Dotted-decimal string (e.g. "192.168.1.1")
42
+ */
43
+ export declare function ipv4ToString(ip: number): string;
44
+ //# sourceMappingURL=ipv4.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipv4.d.ts","sourceRoot":"","sources":["../../src/internal/ipv4.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAa3C,QAAA,MAAM,SAAS,0BAAsB,CAAA;AAErC,OAAO,EAAE,SAAS,EAAE,CAAA;AA4CpB;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAgC1E;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAGlE;AAED;;;;GAIG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAEzC;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAoCzD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE/C"}
@@ -0,0 +1,183 @@
1
+ // --- Constants & lookup tables ---
2
+ // Prebuilt "a.b" strings for all 16-bit values, indexed by (hi_octet << 8 | lo_octet)
3
+ const PAIR_CACHE = new Array(65536);
4
+ for (let i = 0; i < 65536; i++)
5
+ PAIR_CACHE[i] = String((i >>> 8) & 0xFF) + '.' + String(i & 0xFF);
6
+ // Same as PAIR_CACHE but with trailing dot for concatenation in ipv4ToString
7
+ const PAIR_DOT_CACHE = new Array(65536);
8
+ for (let i = 0; i < 65536; i++)
9
+ PAIR_DOT_CACHE[i] = PAIR_CACHE[i] + '.';
10
+ // Subnet masks for prefix lengths 0..32
11
+ const maskV4LUT = new Uint32Array(33);
12
+ for (let i = 1; i <= 32; i++)
13
+ maskV4LUT[i] = (0xFFFFFFFF << (32 - i)) >>> 0;
14
+ export { maskV4LUT };
15
+ // Character classification table: maps charCode to digit value (0-9), dot (0xFE), or invalid (0xFF)
16
+ const V4_CHAR = new Uint8Array(128);
17
+ V4_CHAR.fill(0xFF);
18
+ for (let i = 0; i < 10; i++)
19
+ V4_CHAR[48 + i] = i;
20
+ V4_CHAR[46] = 0xFE;
21
+ // --- Non-exported helpers ---
22
+ function parseAutoInt(s, start, end) {
23
+ if (start >= end)
24
+ return -1;
25
+ const c0 = s.charCodeAt(start);
26
+ if (c0 === 48 && end - start > 1) {
27
+ const c1 = s.charCodeAt(start + 1) | 0x20;
28
+ if (c1 === 0x78) {
29
+ let v = 0;
30
+ for (let i = start + 2; i < end; i++) {
31
+ const ch = s.charCodeAt(i) | 0x20;
32
+ if (ch >= 48 && ch <= 57)
33
+ v = v * 16 + (ch - 48);
34
+ else if (ch >= 97 && ch <= 102)
35
+ v = v * 16 + (ch - 87);
36
+ else
37
+ return -1;
38
+ }
39
+ return v;
40
+ }
41
+ let v = 0;
42
+ for (let i = start; i < end; i++) {
43
+ const ch = s.charCodeAt(i);
44
+ if (ch < 48 || ch > 55)
45
+ return -1;
46
+ v = (v << 3) + (ch - 48);
47
+ }
48
+ return v;
49
+ }
50
+ let v = 0;
51
+ for (let i = start; i < end; i++) {
52
+ const ch = s.charCodeAt(i);
53
+ if (ch < 48 || ch > 57)
54
+ return -1;
55
+ v = v * 10 + (ch - 48);
56
+ }
57
+ return v;
58
+ }
59
+ // --- Exports ---
60
+ /**
61
+ * Parses a strict dotted-decimal IPv4 string into a raw uint32.
62
+ * @param s - Source string
63
+ * @param start - Start index within the string
64
+ * @param end - End index (exclusive) within the string
65
+ * @returns The packed uint32 IP address, or -1 if invalid
66
+ */
67
+ export function parseIPv4Raw(s, start, end) {
68
+ const len = end - start;
69
+ if (len < 7 || len > 15)
70
+ return -1;
71
+ let ip = 0;
72
+ let octet = 0;
73
+ let oStart = start;
74
+ let dot = 0;
75
+ for (let i = start; i < end; i++) {
76
+ const ch = s.charCodeAt(i);
77
+ if (ch >= 128)
78
+ return -1;
79
+ const v = V4_CHAR[ch];
80
+ if (v <= 9) {
81
+ octet = (octet * 10 + v) | 0;
82
+ }
83
+ else if (v === 0xFE) {
84
+ const dLen = i - oStart;
85
+ if (dLen === 0 || dLen > 3 || octet > 255)
86
+ return -1;
87
+ if (dLen > 1 && s.charCodeAt(oStart) === 48)
88
+ return -1;
89
+ ip = ip | (octet << (24 - (dot << 3)));
90
+ octet = 0;
91
+ oStart = i + 1;
92
+ if (++dot > 3)
93
+ return -1;
94
+ }
95
+ else {
96
+ return -1;
97
+ }
98
+ }
99
+ const dLen = end - oStart;
100
+ if (dot !== 3 || dLen === 0 || dLen > 3 || octet > 255)
101
+ return -1;
102
+ if (dLen > 1 && s.charCodeAt(oStart) === 48)
103
+ return -1;
104
+ return (ip | octet) >>> 0;
105
+ }
106
+ /**
107
+ * Parses a strict dotted-decimal IPv4 string into an IPv4Addr.
108
+ * @param s - The IPv4 string (e.g. "192.168.1.1")
109
+ * @param end - Optional end index for parsing a substring
110
+ * @returns The parsed address, or null if invalid
111
+ */
112
+ export function parseIPv4(s, end) {
113
+ const ip = parseIPv4Raw(s, 0, end !== undefined ? end : s.length);
114
+ return ip !== -1 ? { ip, kind: 4 } : null;
115
+ }
116
+ /**
117
+ * Checks whether a string is a valid strict dotted-decimal IPv4 address.
118
+ * @param s - The string to validate
119
+ * @returns True if the string is a valid IPv4 address
120
+ */
121
+ export function isIPv4(s) {
122
+ return parseIPv4Raw(s, 0, s.length) !== -1;
123
+ }
124
+ /**
125
+ * Parses an IPv4 string with relaxed rules: hex (0x), octal (0), and
126
+ * classful shorthand (e.g. "10.1" = "10.0.0.1") are accepted.
127
+ * @param s - The IPv4 string in any accepted notation
128
+ * @returns The parsed address, or null if invalid
129
+ */
130
+ export function parseIPv4Loose(s) {
131
+ const len = s.length;
132
+ if (len === 0)
133
+ return null;
134
+ const dot1 = s.indexOf('.');
135
+ if (dot1 === -1) {
136
+ const v = parseAutoInt(s, 0, len);
137
+ if (v < 0 || v > 0xFFFFFFFF)
138
+ return null;
139
+ return { ip: v >>> 0, kind: 4 };
140
+ }
141
+ const dot2 = s.indexOf('.', dot1 + 1);
142
+ if (dot2 === -1) {
143
+ const a = parseAutoInt(s, 0, dot1);
144
+ const b = parseAutoInt(s, dot1 + 1, len);
145
+ if (a < 0 || a > 255 || b < 0 || b > 0xFFFFFF)
146
+ return null;
147
+ return { ip: ((a << 24) | (b & 0xFFFFFF)) >>> 0, kind: 4 };
148
+ }
149
+ const dot3 = s.indexOf('.', dot2 + 1);
150
+ if (dot3 === -1) {
151
+ const a = parseAutoInt(s, 0, dot1);
152
+ const b = parseAutoInt(s, dot1 + 1, dot2);
153
+ const c = parseAutoInt(s, dot2 + 1, len);
154
+ if (a < 0 || a > 255 || b < 0 || b > 255 || c < 0 || c > 0xFFFF)
155
+ return null;
156
+ return { ip: ((a << 24) | (b << 16) | (c & 0xFFFF)) >>> 0, kind: 4 };
157
+ }
158
+ if (s.indexOf('.', dot3 + 1) !== -1)
159
+ return null;
160
+ const a = parseAutoInt(s, 0, dot1);
161
+ const b = parseAutoInt(s, dot1 + 1, dot2);
162
+ const c = parseAutoInt(s, dot2 + 1, dot3);
163
+ const d = parseAutoInt(s, dot3 + 1, len);
164
+ if (a < 0 || a > 255 || b < 0 || b > 255 || c < 0 || c > 255 || d < 0 || d > 255)
165
+ return null;
166
+ return { ip: ((a << 24) | (b << 16) | (c << 8) | d) >>> 0, kind: 4 };
167
+ }
168
+ /**
169
+ * Extracts the four octets of a packed uint32 IPv4 address.
170
+ * @param ip - Packed uint32 IP address
171
+ * @returns Tuple of four octets [a, b, c, d]
172
+ */
173
+ export function ipv4ToOctets(ip) {
174
+ return [ip >>> 24, (ip >>> 16) & 0xFF, (ip >>> 8) & 0xFF, ip & 0xFF];
175
+ }
176
+ /**
177
+ * Converts a packed uint32 IPv4 address to dotted-decimal string.
178
+ * @param ip - Packed uint32 IP address
179
+ * @returns Dotted-decimal string (e.g. "192.168.1.1")
180
+ */
181
+ export function ipv4ToString(ip) {
182
+ return PAIR_DOT_CACHE[ip >>> 16] + PAIR_CACHE[ip & 0xFFFF];
183
+ }
@@ -0,0 +1,47 @@
1
+ import type { IPv6Addr, IPv6RangeName } from '../types.ts';
2
+ /**
3
+ * Tests whether an IPv6 address matches a CIDR prefix using raw uint32 words.
4
+ * @param aw0 - Address word 0 (bits 0-31)
5
+ * @param aw1 - Address word 1 (bits 32-63)
6
+ * @param aw2 - Address word 2 (bits 64-95)
7
+ * @param aw3 - Address word 3 (bits 96-127)
8
+ * @param nw0 - Network word 0
9
+ * @param nw1 - Network word 1
10
+ * @param nw2 - Network word 2
11
+ * @param nw3 - Network word 3
12
+ * @param prefix - Prefix length (0-128)
13
+ * @returns True if the address is within the network prefix
14
+ */
15
+ export declare function matchesCidr(aw0: number, aw1: number, aw2: number, aw3: number, nw0: number, nw1: number, nw2: number, nw3: number, prefix: number): boolean;
16
+ /**
17
+ * Computes the bitmask for a specific 32-bit word of an IPv6 prefix.
18
+ * @param prefix - Prefix length (0-128)
19
+ * @param wordOffset - Which 32-bit word (0-3)
20
+ * @returns The uint32 mask for that word
21
+ */
22
+ export declare function prefixMaskV6(prefix: number, wordOffset: number): number;
23
+ /**
24
+ * Classifies an IPv6 address into its IANA-assigned range.
25
+ * @param addr - The IPv6 address
26
+ * @returns The range name (e.g. "uniqueLocal", "loopback", "unicast")
27
+ */
28
+ export declare function ipv6Range(addr: IPv6Addr): IPv6RangeName;
29
+ /**
30
+ * Checks whether an IPv6 address is private (unique-local, multicast, link-local, or loopback).
31
+ * @param addr - The IPv6 address
32
+ * @returns True if the address is non-globally-routable
33
+ */
34
+ export declare function isPrivateIPv6(addr: IPv6Addr): boolean;
35
+ /**
36
+ * Checks whether an IPv6 address is the loopback address (::1).
37
+ * @param addr - The IPv6 address
38
+ * @returns True if the address is ::1
39
+ */
40
+ export declare function isLoopbackIPv6(addr: IPv6Addr): boolean;
41
+ /**
42
+ * Checks whether an IPv6 address is link-local (fe80::/10).
43
+ * @param addr - The IPv6 address
44
+ * @returns True if the address is in the link-local range
45
+ */
46
+ export declare function isLinkLocalIPv6(addr: IPv6Addr): boolean;
47
+ //# sourceMappingURL=ipv6-ranges.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ipv6-ranges.d.ts","sourceRoot":"","sources":["../../src/internal/ipv6-ranges.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AA2C1D;;;;;;;;;;;;GAYG;AACH,wBAAgB,WAAW,CACzB,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAClD,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAClD,MAAM,EAAE,MAAM,GACb,OAAO,CA0BT;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAMvE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,QAAQ,GAAG,aAAa,CAqBvD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAOrD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEtD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAEvD"}