node-ip-ts 1.2.1 → 1.2.3

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 (2) hide show
  1. package/README.md +473 -463
  2. package/package.json +2 -2
package/README.md CHANGED
@@ -1,463 +1,473 @@
1
- <div align="center">
2
-
3
- <br />
4
-
5
- ```
6
- ___ ____ _____ ____
7
- |_ _| _ \ |_ _/ ___|
8
- | || |_) |_____| | \___ \
9
- | || __/_____| | ___) |
10
- |___|_| |_| |____/
11
- ```
12
-
13
- ### A modern, type-safe IP address utility library for Node.js
14
-
15
- [![npm version](https://img.shields.io/npm/v/node-ip-ts?color=0ea5e9&style=flat-square)](https://www.npmjs.com/package/node-ip-ts)
16
- [![license](https://img.shields.io/npm/l/node-ip-ts?color=0ea5e9&style=flat-square)](./LICENSE)
17
- [![types](https://img.shields.io/npm/types/node-ip-ts?style=flat-square)](https://www.npmjs.com/package/node-ip-ts)
18
- [![zero deps](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square)](./package.json)
19
-
20
- <br />
21
-
22
- **node-ip-ts** is a full TypeScript rewrite of the popular [`ip`](https://www.npmjs.com/package/ip) package —
23
- rebuilt from the ground up with strict types, ES Modules, and zero external dependencies.
24
-
25
- [Installation](#installation) · [Quick Start](#quick-start) · [API Reference](#api-reference) · [Contributing](#contributing)
26
-
27
- <br />
28
-
29
- </div>
30
-
31
- ---
32
-
33
- ## Why node-ip-ts?
34
-
35
- The original `ip` package has millions of weekly downloads but ships no TypeScript types and only supports CommonJS. **node-ip-ts** solves that:
36
-
37
- | | `ip` | `node-ip-ts` |
38
- |---|:---:|:---:|
39
- | TypeScript support | ❌ | ✅ |
40
- | ES Module support | ❌ | ✅ |
41
- | CommonJS support | ✅ | ✅ |
42
- | Type declarations | ❌ | ✅ |
43
- | Strict null checks | ❌ | ✅ |
44
- | External dependencies | 0 | 0 |
45
- | API compatibility | | drop-in |
46
-
47
- ---
48
-
49
- ## Browser Compatibility
50
-
51
- All functions **except `address()`** work in both Node.js and browser/bundler environments (Vite, webpack, esbuild, etc.).
52
-
53
- | Function | Node.js | Browser |
54
- |---|:---:|:---:|
55
- | All IP/subnet/bitwise functions | | ✅ |
56
- | `loopback()` | ✅ | ✅ |
57
- | `address()` | ✅ | ❌ (uses `os` module) |
58
-
59
- If you need an IP in a browser context, obtain it server-side and pass it to the client, or use `loopback()` as a fallback.
60
-
61
- ---
62
-
63
- ## Installation
64
-
65
- ```bash
66
- # npm
67
- npm install node-ip-ts
68
-
69
- # pnpm
70
- pnpm add node-ip-ts
71
-
72
- # yarn
73
- yarn add node-ip-ts
74
- ```
75
-
76
- > **Requirements:** Node.js ≥ 16
77
-
78
- ---
79
-
80
- ## Quick Start
81
-
82
- ### ESM / TypeScript
83
-
84
- ```ts
85
- import * as ip from 'node-ip-ts';
86
-
87
- // Address classification
88
- ip.isPrivate('192.168.1.1'); // true
89
- ip.isPublic('8.8.8.8'); // true
90
- ip.isLoopback('127.0.0.1'); // true
91
-
92
- // Subnet operations
93
- ip.cidr('192.168.1.134/26'); // '192.168.1.128'
94
- const subnet = ip.cidrSubnet('192.168.1.134/26');
95
- subnet.contains('192.168.1.180'); // true
96
-
97
- // Conversion
98
- ip.toLong('255.255.255.255'); // 4294967295
99
- ip.fromLong(4294967295); // '255.255.255.255'
100
- ```
101
-
102
- ### Named imports (tree-shakeable)
103
-
104
- ```ts
105
- import { isPrivate, cidrSubnet, toLong } from 'node-ip-ts';
106
- ```
107
-
108
- ### CommonJS
109
-
110
- ```js
111
- const ip = require('node-ip-ts');
112
- ip.isPrivate('10.0.0.1'); // true
113
- ```
114
-
115
- ---
116
-
117
- ## API Reference
118
-
119
- ### Address Classification
120
-
121
- #### `isPrivate(addr: string): boolean`
122
-
123
- Returns `true` if the address falls within any private/reserved range:
124
- - `10.0.0.0/8` — RFC 1918
125
- - `172.16.0.0/12` — RFC 1918
126
- - `192.168.0.0/16` — RFC 1918
127
- - `169.254.0.0/16` — link-local
128
- - `fc00::/7` — IPv6 ULA
129
- - `fe80::/10` — IPv6 link-local
130
- - `::1`, `::` — loopback
131
-
132
- ```ts
133
- ip.isPrivate('192.168.0.1'); // true
134
- ip.isPrivate('10.0.0.1'); // true
135
- ip.isPrivate('fd12:3456:789a:1::1'); // true (IPv6 ULA)
136
- ip.isPrivate('::ffff:192.168.0.1'); // true (IPv4-mapped IPv6)
137
- ip.isPrivate('8.8.8.8'); // false
138
- ```
139
-
140
- #### `isPublic(addr: string): boolean`
141
-
142
- Inverse of `isPrivate`. Returns `true` for publicly routable addresses.
143
-
144
- ```ts
145
- ip.isPublic('1.1.1.1'); // true
146
- ip.isPublic('10.0.0.1'); // false
147
- ```
148
-
149
- #### `isLoopback(addr: string): boolean`
150
-
151
- Returns `true` for loopback addresses. Supports dotted-decimal, octal, hexadecimal, and long-integer notation.
152
-
153
- ```ts
154
- ip.isLoopback('127.0.0.1'); // true
155
- ip.isLoopback('::1'); // true
156
- ip.isLoopback('0x7f.0.0.1'); // true (hex notation)
157
- ip.isLoopback('0177.0.0.1'); // true (octal notation)
158
- ip.isLoopback('2130706433'); // true (integer notation)
159
- ip.isLoopback('8.8.8.8'); // false
160
- ```
161
-
162
- #### `isV4Format(ip: string): boolean`
163
-
164
- ```ts
165
- ip.isV4Format('192.168.0.1'); // true
166
- ip.isV4Format('::1'); // false
167
- ```
168
-
169
- #### `isV6Format(ip: string): boolean`
170
-
171
- ```ts
172
- ip.isV6Format('::1'); // true
173
- ip.isV6Format('::ffff:192.168.0.1'); // true
174
- ip.isV6Format('192.168.0.1'); // false
175
- ```
176
-
177
- ---
178
-
179
- ### Subnet & CIDR
180
-
181
- #### `cidr(cidrString: string): string`
182
-
183
- Returns the network address for a given CIDR string.
184
-
185
- ```ts
186
- ip.cidr('192.168.1.134/26'); // '192.168.1.128'
187
- ip.cidr('2607:f0d0:1002:51::4/56'); // '2607:f0d0:1002::'
188
- ```
189
-
190
- #### `cidrSubnet(cidrString: string): SubnetInfo`
191
-
192
- Returns a full `SubnetInfo` object for a given CIDR string.
193
-
194
- ```ts
195
- const s = ip.cidrSubnet('192.168.1.134/26');
196
-
197
- s.networkAddress; // '192.168.1.128'
198
- s.firstAddress; // '192.168.1.129'
199
- s.lastAddress; // '192.168.1.190'
200
- s.broadcastAddress; // '192.168.1.191'
201
- s.subnetMask; // '255.255.255.192'
202
- s.subnetMaskLength; // 26
203
- s.numHosts; // 62
204
- s.length; // 64
205
- s.contains('192.168.1.150'); // true
206
- s.contains('192.168.1.200'); // false
207
- ```
208
-
209
- #### `subnet(addr: string, mask: string): SubnetInfo`
210
-
211
- Same as `cidrSubnet` but takes address and mask separately.
212
-
213
- ```ts
214
- const s = ip.subnet('192.168.1.134', '255.255.255.192');
215
- ```
216
-
217
- #### `mask(addr: string, mask: string): string`
218
-
219
- Applies a subnet mask to an address via bitwise AND.
220
-
221
- ```ts
222
- ip.mask('192.168.1.134', '255.255.255.0'); // '192.168.1.0'
223
- ip.mask('192.168.1.134', '::ffff:ff00'); // '::ffff:c0a8:100'
224
- ```
225
-
226
- #### `fromPrefixLen(prefixlen: number, family?: string | number): string`
227
-
228
- Converts a prefix length to a subnet mask string.
229
-
230
- ```ts
231
- ip.fromPrefixLen(24); // '255.255.255.0'
232
- ip.fromPrefixLen(64); // 'ffff:ffff:ffff:ffff::' (auto-detects IPv6)
233
- ip.fromPrefixLen(24, 'ipv6'); // 'ffff:ff00::'
234
- ```
235
-
236
- ---
237
-
238
- ### Bitwise Operations
239
-
240
- #### `not(addr: string): string`
241
-
242
- Bitwise NOT — useful for computing wildcard masks.
243
-
244
- ```ts
245
- ip.not('255.255.255.0'); // '0.0.0.255'
246
- ```
247
-
248
- #### `or(a: string, b: string): string`
249
-
250
- Bitwise OR. Supports same-protocol and mixed IPv4/IPv6 inputs.
251
-
252
- ```ts
253
- ip.or('0.0.0.255', '192.168.1.10'); // '192.168.1.255'
254
- ip.or('::ff', '::abcd:dcba:abcd:dcba'); // '::abcd:dcba:abcd:dcff'
255
- ip.or('0.0.0.255', '::abcd:dcba:abcd:dcba'); // '::abcd:dcba:abcd:dcff'
256
- ```
257
-
258
- #### `isEqual(a: string, b: string): boolean`
259
-
260
- Deep equality check, IPv4/IPv6 aware (e.g. `127.0.0.1` equals `::ffff:7f00:1`).
261
-
262
- ```ts
263
- ip.isEqual('127.0.0.1', '::ffff:127.0.0.1'); // true
264
- ip.isEqual('127.0.0.1', '::7f00:1'); // true
265
- ip.isEqual('127.0.0.1', '::7f00:2'); // false
266
- ```
267
-
268
- ---
269
-
270
- ### Buffer Conversion
271
-
272
- #### `toBuffer(ip: string, buff?: Buffer, offset?: number): Buffer`
273
-
274
- Converts an IP string to a raw `Buffer` (4 bytes for IPv4, 16 for IPv6). Optionally writes into an existing buffer at a given offset.
275
-
276
- ```ts
277
- ip.toBuffer('127.0.0.1');
278
- // <Buffer 7f 00 00 01>
279
-
280
- const buf = Buffer.alloc(128);
281
- ip.toBuffer('127.0.0.1', buf, 64);
282
- // writes 4 bytes into buf at offset 64
283
- ```
284
-
285
- #### `toString(buff: Buffer, offset?: number, length?: number): string`
286
-
287
- Converts a `Buffer` back to an IP address string.
288
-
289
- ```ts
290
- ip.toString(Buffer.from('7f000001', 'hex')); // '127.0.0.1'
291
- ip.toString(buf, 64, 4); // '127.0.0.1'
292
- ```
293
-
294
- ---
295
-
296
- ### Long Integer Conversion
297
-
298
- #### `toLong(ip: string): number`
299
-
300
- Converts a dotted-decimal IPv4 address to an unsigned 32-bit integer.
301
-
302
- ```ts
303
- ip.toLong('127.0.0.1'); // 2130706433
304
- ip.toLong('255.255.255.255'); // 4294967295
305
- ```
306
-
307
- #### `fromLong(ipl: number): string`
308
-
309
- Converts an unsigned 32-bit integer back to dotted-decimal.
310
-
311
- ```ts
312
- ip.fromLong(2130706433); // '127.0.0.1'
313
- ip.fromLong(4294967295); // '255.255.255.255'
314
- ```
315
-
316
- #### `normalizeToLong(addr: string): number`
317
-
318
- Normalizes an IPv4 address in any notation (decimal, octal, hex, compact) to an unsigned long. Returns `-1` on invalid input.
319
-
320
- ```ts
321
- ip.normalizeToLong('127.0.0.1'); // 2130706433 (standard)
322
- ip.normalizeToLong('0x7f.0x0.0x0.1'); // 2130706433 (hex)
323
- ip.normalizeToLong('0177.0.0.01'); // 2130706433 (octal)
324
- ip.normalizeToLong('0x7f000001'); // 2130706433 (single hex)
325
- ip.normalizeToLong('127.1'); // 2130706433 (compact)
326
- ip.normalizeToLong('256.0.0.1'); // -1 (invalid)
327
- ```
328
-
329
- ---
330
-
331
- ### Network Interface
332
-
333
- #### `address(name?: string, family?: string | number): string`
334
-
335
- > ⚠️ **Node.js only.** This function uses the `os` module which is not available in browsers.
336
- > Calling it in a browser environment will throw a descriptive error. All other functions work in both environments.
337
-
338
- Returns an IP address from the current machine's network interfaces.
339
-
340
- ```ts
341
- ip.address(); // first private IPv4 address, e.g. '192.168.1.42'
342
- ip.address('public'); // first public IPv4 address
343
- ip.address('private'); // first private IPv4 address
344
- ip.address('eth0'); // first IPv4 address on eth0
345
- ip.address('eth0', 6); // first IPv6 address on eth0
346
- ```
347
-
348
- Falls back to `loopback()` if no matching interface is found.
349
-
350
- #### `loopback(family?: string | number): string`
351
-
352
- Returns the loopback address for the given IP family.
353
-
354
- ```ts
355
- ip.loopback(); // '127.0.0.1'
356
- ip.loopback('ipv4'); // '127.0.0.1'
357
- ip.loopback('ipv6'); // 'fe80::1'
358
- ```
359
-
360
- ---
361
-
362
- ### Types
363
-
364
- ```ts
365
- import type { IPFamily, SubnetInfo } from 'node-ip-ts';
366
-
367
- type IPFamily = 'ipv4' | 'ipv6';
368
-
369
- interface SubnetInfo {
370
- networkAddress: string;
371
- firstAddress: string;
372
- lastAddress: string;
373
- broadcastAddress: string;
374
- subnetMask: string;
375
- subnetMaskLength: number;
376
- numHosts: number;
377
- length: number;
378
- contains(other: string): boolean;
379
- }
380
- ```
381
-
382
- ---
383
-
384
- ## Project Structure
385
-
386
- ```
387
- node-ip-ts/
388
- ├── src/
389
- │ └── index.ts # Single source file — all named exports
390
- ├── dist/
391
- │ ├── esm/ # ES Module build (.js + .js.map)
392
- │ ├── cjs/ # CommonJS build (.js + .js.map)
393
- │ └── types/ # Type declarations (.d.ts + .d.ts.map)
394
- ├── __tests__/
395
- │ └── ip.test.ts # Jest test suite
396
- ├── tsconfig.esm.json
397
- ├── tsconfig.cjs.json
398
- ├── tsconfig.types.json
399
- └── package.json
400
- ```
401
-
402
- ---
403
-
404
- ## Contributing
405
-
406
- Contributions are welcome! Here's how to get started:
407
-
408
- ```bash
409
- # Clone the repo
410
- git clone https://github.com/your-org/node-ip-ts.git
411
- cd node-ip-ts
412
-
413
- # Install dependencies
414
- npm install
415
-
416
- # Run tests
417
- npm test
418
-
419
- # Build
420
- npm run build
421
- ```
422
-
423
- ### Guidelines
424
-
425
- - All changes must pass the existing test suite (`npm test`)
426
- - New features must include corresponding tests
427
- - Code must pass TypeScript strict mode
428
- - Keep zero external runtime dependencies
429
-
430
- ### Reporting Issues
431
-
432
- Please [open an issue](https://github.com/your-org/node-ip-ts/issues/new) with a minimal reproduction case.
433
-
434
- ---
435
-
436
- ## Migration from `ip`
437
-
438
- **node-ip-ts** is designed to be a drop-in replacement. Simply swap your import:
439
-
440
- ```diff
441
- - const ip = require('ip');
442
- + const ip = require('node-ip-ts');
443
- ```
444
-
445
- Or for TypeScript / ESM:
446
-
447
- ```ts
448
- import * as ip from 'node-ip-ts';
449
- ```
450
-
451
- All function names and behaviours are identical to the original library.
452
-
453
- ---
454
-
455
- ## License
456
-
457
- [MIT](./LICENSE) © your-org
458
-
459
- ---
460
-
461
- <div align="center">
462
- <sub>If this library saved you time, consider giving it a ⭐ on GitHub.</sub>
463
- </div>
1
+ <div align="center">
2
+
3
+ <br />
4
+
5
+ ```
6
+ ___ ____ _____ ____
7
+ |_ _| _ \ |_ _/ ___|
8
+ | || |_) |_____| | \___ \
9
+ | || __/_____| | ___) |
10
+ |___|_| |_| |____/
11
+ ```
12
+
13
+ ### A modern, type-safe IP address utility library for Node.js
14
+
15
+ # node-ip-ts
16
+
17
+ <!-- Package Info -->
18
+ [![npm version](https://img.shields.io/npm/v/node-ip-ts?color=0ea5e9&style=flat-square)](https://www.npmjs.com/package/node-ip-ts)
19
+ [![npm downloads](https://img.shields.io/npm/dw/node-ip-ts?color=0ea5e9&style=flat-square)](https://www.npmjs.com/package/node-ip-ts)
20
+ [![license](https://img.shields.io/npm/l/node-ip-ts?color=0ea5e9&style=flat-square)](./LICENSE)
21
+
22
+ <!-- Tech Quality -->
23
+ [![TypeScript](https://img.shields.io/npm/types/node-ip-ts?style=flat-square)](https://www.npmjs.com/package/node-ip-ts)
24
+ [![zero dependencies](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square)](./package.json)
25
+
26
+ <!-- Security -->
27
+ [![Snyk Security](https://snyk.io/test/github/denycode-dev/ip-ts/badge.svg?style=flat-square)](https://snyk.io/test/github/denycode-dev/ip-ts)
28
+ [![Socket Security](https://badge.socket.dev/npm/package/node-ip-ts)](https://socket.dev/npm/package/node-ip-ts)
29
+
30
+ <br />
31
+
32
+ **node-ip-ts** is a full TypeScript rewrite of the popular [`ip`](https://www.npmjs.com/package/ip) package —
33
+ rebuilt from the ground up with strict types, ES Modules, and zero external dependencies.
34
+
35
+ [Installation](#installation) · [Quick Start](#quick-start) · [API Reference](#api-reference) · [Contributing](#contributing)
36
+
37
+ <br />
38
+
39
+ </div>
40
+
41
+ ---
42
+
43
+ ## Why node-ip-ts?
44
+
45
+ The original `ip` package has millions of weekly downloads but ships no TypeScript types and only supports CommonJS. **node-ip-ts** solves that:
46
+
47
+ | | `ip` | `node-ip-ts` |
48
+ |---|:---:|:---:|
49
+ | TypeScript support | ❌ | ✅ |
50
+ | ES Module support | ❌ | ✅ |
51
+ | CommonJS support | | |
52
+ | Type declarations | ❌ | ✅ |
53
+ | Strict null checks | | |
54
+ | External dependencies | 0 | 0 |
55
+ | API compatibility | | ✅ drop-in |
56
+
57
+ ---
58
+
59
+ ## Browser Compatibility
60
+
61
+ All functions **except `address()`** work in both Node.js and browser/bundler environments (Vite, webpack, esbuild, etc.).
62
+
63
+ | Function | Node.js | Browser |
64
+ |---|:---:|:---:|
65
+ | All IP/subnet/bitwise functions | ✅ | ✅ |
66
+ | `loopback()` | ✅ | ✅ |
67
+ | `address()` | ✅ | ❌ (uses `os` module) |
68
+
69
+ If you need an IP in a browser context, obtain it server-side and pass it to the client, or use `loopback()` as a fallback.
70
+
71
+ ---
72
+
73
+ ## Installation
74
+
75
+ ```bash
76
+ # npm
77
+ npm install node-ip-ts
78
+
79
+ # pnpm
80
+ pnpm add node-ip-ts
81
+
82
+ # yarn
83
+ yarn add node-ip-ts
84
+ ```
85
+
86
+ > **Requirements:** Node.js ≥ 16
87
+
88
+ ---
89
+
90
+ ## Quick Start
91
+
92
+ ### ESM / TypeScript
93
+
94
+ ```ts
95
+ import * as ip from 'node-ip-ts';
96
+
97
+ // Address classification
98
+ ip.isPrivate('192.168.1.1'); // true
99
+ ip.isPublic('8.8.8.8'); // true
100
+ ip.isLoopback('127.0.0.1'); // true
101
+
102
+ // Subnet operations
103
+ ip.cidr('192.168.1.134/26'); // '192.168.1.128'
104
+ const subnet = ip.cidrSubnet('192.168.1.134/26');
105
+ subnet.contains('192.168.1.180'); // true
106
+
107
+ // Conversion
108
+ ip.toLong('255.255.255.255'); // 4294967295
109
+ ip.fromLong(4294967295); // '255.255.255.255'
110
+ ```
111
+
112
+ ### Named imports (tree-shakeable)
113
+
114
+ ```ts
115
+ import { isPrivate, cidrSubnet, toLong } from 'node-ip-ts';
116
+ ```
117
+
118
+ ### CommonJS
119
+
120
+ ```js
121
+ const ip = require('node-ip-ts');
122
+ ip.isPrivate('10.0.0.1'); // true
123
+ ```
124
+
125
+ ---
126
+
127
+ ## API Reference
128
+
129
+ ### Address Classification
130
+
131
+ #### `isPrivate(addr: string): boolean`
132
+
133
+ Returns `true` if the address falls within any private/reserved range:
134
+ - `10.0.0.0/8` — RFC 1918
135
+ - `172.16.0.0/12` RFC 1918
136
+ - `192.168.0.0/16` RFC 1918
137
+ - `169.254.0.0/16` — link-local
138
+ - `fc00::/7` — IPv6 ULA
139
+ - `fe80::/10` — IPv6 link-local
140
+ - `::1`, `::` — loopback
141
+
142
+ ```ts
143
+ ip.isPrivate('192.168.0.1'); // true
144
+ ip.isPrivate('10.0.0.1'); // true
145
+ ip.isPrivate('fd12:3456:789a:1::1'); // true (IPv6 ULA)
146
+ ip.isPrivate('::ffff:192.168.0.1'); // true (IPv4-mapped IPv6)
147
+ ip.isPrivate('8.8.8.8'); // false
148
+ ```
149
+
150
+ #### `isPublic(addr: string): boolean`
151
+
152
+ Inverse of `isPrivate`. Returns `true` for publicly routable addresses.
153
+
154
+ ```ts
155
+ ip.isPublic('1.1.1.1'); // true
156
+ ip.isPublic('10.0.0.1'); // false
157
+ ```
158
+
159
+ #### `isLoopback(addr: string): boolean`
160
+
161
+ Returns `true` for loopback addresses. Supports dotted-decimal, octal, hexadecimal, and long-integer notation.
162
+
163
+ ```ts
164
+ ip.isLoopback('127.0.0.1'); // true
165
+ ip.isLoopback('::1'); // true
166
+ ip.isLoopback('0x7f.0.0.1'); // true (hex notation)
167
+ ip.isLoopback('0177.0.0.1'); // true (octal notation)
168
+ ip.isLoopback('2130706433'); // true (integer notation)
169
+ ip.isLoopback('8.8.8.8'); // false
170
+ ```
171
+
172
+ #### `isV4Format(ip: string): boolean`
173
+
174
+ ```ts
175
+ ip.isV4Format('192.168.0.1'); // true
176
+ ip.isV4Format('::1'); // false
177
+ ```
178
+
179
+ #### `isV6Format(ip: string): boolean`
180
+
181
+ ```ts
182
+ ip.isV6Format('::1'); // true
183
+ ip.isV6Format('::ffff:192.168.0.1'); // true
184
+ ip.isV6Format('192.168.0.1'); // false
185
+ ```
186
+
187
+ ---
188
+
189
+ ### Subnet & CIDR
190
+
191
+ #### `cidr(cidrString: string): string`
192
+
193
+ Returns the network address for a given CIDR string.
194
+
195
+ ```ts
196
+ ip.cidr('192.168.1.134/26'); // '192.168.1.128'
197
+ ip.cidr('2607:f0d0:1002:51::4/56'); // '2607:f0d0:1002::'
198
+ ```
199
+
200
+ #### `cidrSubnet(cidrString: string): SubnetInfo`
201
+
202
+ Returns a full `SubnetInfo` object for a given CIDR string.
203
+
204
+ ```ts
205
+ const s = ip.cidrSubnet('192.168.1.134/26');
206
+
207
+ s.networkAddress; // '192.168.1.128'
208
+ s.firstAddress; // '192.168.1.129'
209
+ s.lastAddress; // '192.168.1.190'
210
+ s.broadcastAddress; // '192.168.1.191'
211
+ s.subnetMask; // '255.255.255.192'
212
+ s.subnetMaskLength; // 26
213
+ s.numHosts; // 62
214
+ s.length; // 64
215
+ s.contains('192.168.1.150'); // true
216
+ s.contains('192.168.1.200'); // false
217
+ ```
218
+
219
+ #### `subnet(addr: string, mask: string): SubnetInfo`
220
+
221
+ Same as `cidrSubnet` but takes address and mask separately.
222
+
223
+ ```ts
224
+ const s = ip.subnet('192.168.1.134', '255.255.255.192');
225
+ ```
226
+
227
+ #### `mask(addr: string, mask: string): string`
228
+
229
+ Applies a subnet mask to an address via bitwise AND.
230
+
231
+ ```ts
232
+ ip.mask('192.168.1.134', '255.255.255.0'); // '192.168.1.0'
233
+ ip.mask('192.168.1.134', '::ffff:ff00'); // '::ffff:c0a8:100'
234
+ ```
235
+
236
+ #### `fromPrefixLen(prefixlen: number, family?: string | number): string`
237
+
238
+ Converts a prefix length to a subnet mask string.
239
+
240
+ ```ts
241
+ ip.fromPrefixLen(24); // '255.255.255.0'
242
+ ip.fromPrefixLen(64); // 'ffff:ffff:ffff:ffff::' (auto-detects IPv6)
243
+ ip.fromPrefixLen(24, 'ipv6'); // 'ffff:ff00::'
244
+ ```
245
+
246
+ ---
247
+
248
+ ### Bitwise Operations
249
+
250
+ #### `not(addr: string): string`
251
+
252
+ Bitwise NOT — useful for computing wildcard masks.
253
+
254
+ ```ts
255
+ ip.not('255.255.255.0'); // '0.0.0.255'
256
+ ```
257
+
258
+ #### `or(a: string, b: string): string`
259
+
260
+ Bitwise OR. Supports same-protocol and mixed IPv4/IPv6 inputs.
261
+
262
+ ```ts
263
+ ip.or('0.0.0.255', '192.168.1.10'); // '192.168.1.255'
264
+ ip.or('::ff', '::abcd:dcba:abcd:dcba'); // '::abcd:dcba:abcd:dcff'
265
+ ip.or('0.0.0.255', '::abcd:dcba:abcd:dcba'); // '::abcd:dcba:abcd:dcff'
266
+ ```
267
+
268
+ #### `isEqual(a: string, b: string): boolean`
269
+
270
+ Deep equality check, IPv4/IPv6 aware (e.g. `127.0.0.1` equals `::ffff:7f00:1`).
271
+
272
+ ```ts
273
+ ip.isEqual('127.0.0.1', '::ffff:127.0.0.1'); // true
274
+ ip.isEqual('127.0.0.1', '::7f00:1'); // true
275
+ ip.isEqual('127.0.0.1', '::7f00:2'); // false
276
+ ```
277
+
278
+ ---
279
+
280
+ ### Buffer Conversion
281
+
282
+ #### `toBuffer(ip: string, buff?: Buffer, offset?: number): Buffer`
283
+
284
+ Converts an IP string to a raw `Buffer` (4 bytes for IPv4, 16 for IPv6). Optionally writes into an existing buffer at a given offset.
285
+
286
+ ```ts
287
+ ip.toBuffer('127.0.0.1');
288
+ // <Buffer 7f 00 00 01>
289
+
290
+ const buf = Buffer.alloc(128);
291
+ ip.toBuffer('127.0.0.1', buf, 64);
292
+ // writes 4 bytes into buf at offset 64
293
+ ```
294
+
295
+ #### `toString(buff: Buffer, offset?: number, length?: number): string`
296
+
297
+ Converts a `Buffer` back to an IP address string.
298
+
299
+ ```ts
300
+ ip.toString(Buffer.from('7f000001', 'hex')); // '127.0.0.1'
301
+ ip.toString(buf, 64, 4); // '127.0.0.1'
302
+ ```
303
+
304
+ ---
305
+
306
+ ### Long Integer Conversion
307
+
308
+ #### `toLong(ip: string): number`
309
+
310
+ Converts a dotted-decimal IPv4 address to an unsigned 32-bit integer.
311
+
312
+ ```ts
313
+ ip.toLong('127.0.0.1'); // 2130706433
314
+ ip.toLong('255.255.255.255'); // 4294967295
315
+ ```
316
+
317
+ #### `fromLong(ipl: number): string`
318
+
319
+ Converts an unsigned 32-bit integer back to dotted-decimal.
320
+
321
+ ```ts
322
+ ip.fromLong(2130706433); // '127.0.0.1'
323
+ ip.fromLong(4294967295); // '255.255.255.255'
324
+ ```
325
+
326
+ #### `normalizeToLong(addr: string): number`
327
+
328
+ Normalizes an IPv4 address in any notation (decimal, octal, hex, compact) to an unsigned long. Returns `-1` on invalid input.
329
+
330
+ ```ts
331
+ ip.normalizeToLong('127.0.0.1'); // 2130706433 (standard)
332
+ ip.normalizeToLong('0x7f.0x0.0x0.1'); // 2130706433 (hex)
333
+ ip.normalizeToLong('0177.0.0.01'); // 2130706433 (octal)
334
+ ip.normalizeToLong('0x7f000001'); // 2130706433 (single hex)
335
+ ip.normalizeToLong('127.1'); // 2130706433 (compact)
336
+ ip.normalizeToLong('256.0.0.1'); // -1 (invalid)
337
+ ```
338
+
339
+ ---
340
+
341
+ ### Network Interface
342
+
343
+ #### `address(name?: string, family?: string | number): string`
344
+
345
+ > ⚠️ **Node.js only.** This function uses the `os` module which is not available in browsers.
346
+ > Calling it in a browser environment will throw a descriptive error. All other functions work in both environments.
347
+
348
+ Returns an IP address from the current machine's network interfaces.
349
+
350
+ ```ts
351
+ ip.address(); // first private IPv4 address, e.g. '192.168.1.42'
352
+ ip.address('public'); // first public IPv4 address
353
+ ip.address('private'); // first private IPv4 address
354
+ ip.address('eth0'); // first IPv4 address on eth0
355
+ ip.address('eth0', 6); // first IPv6 address on eth0
356
+ ```
357
+
358
+ Falls back to `loopback()` if no matching interface is found.
359
+
360
+ #### `loopback(family?: string | number): string`
361
+
362
+ Returns the loopback address for the given IP family.
363
+
364
+ ```ts
365
+ ip.loopback(); // '127.0.0.1'
366
+ ip.loopback('ipv4'); // '127.0.0.1'
367
+ ip.loopback('ipv6'); // 'fe80::1'
368
+ ```
369
+
370
+ ---
371
+
372
+ ### Types
373
+
374
+ ```ts
375
+ import type { IPFamily, SubnetInfo } from 'node-ip-ts';
376
+
377
+ type IPFamily = 'ipv4' | 'ipv6';
378
+
379
+ interface SubnetInfo {
380
+ networkAddress: string;
381
+ firstAddress: string;
382
+ lastAddress: string;
383
+ broadcastAddress: string;
384
+ subnetMask: string;
385
+ subnetMaskLength: number;
386
+ numHosts: number;
387
+ length: number;
388
+ contains(other: string): boolean;
389
+ }
390
+ ```
391
+
392
+ ---
393
+
394
+ ## Project Structure
395
+
396
+ ```
397
+ node-ip-ts/
398
+ ├── src/
399
+ └── index.ts # Single source file — all named exports
400
+ ├── dist/
401
+ │ ├── esm/ # ES Module build (.js + .js.map)
402
+ │ ├── cjs/ # CommonJS build (.js + .js.map)
403
+ │ └── types/ # Type declarations (.d.ts + .d.ts.map)
404
+ ├── __tests__/
405
+ │ └── ip.test.ts # Jest test suite
406
+ ├── tsconfig.esm.json
407
+ ├── tsconfig.cjs.json
408
+ ├── tsconfig.types.json
409
+ └── package.json
410
+ ```
411
+
412
+ ---
413
+
414
+ ## Contributing
415
+
416
+ Contributions are welcome! Here's how to get started:
417
+
418
+ ```bash
419
+ # Clone the repo
420
+ git clone https://github.com/denycode-dev/ip-ts.git
421
+ cd node-ip-ts
422
+
423
+ # Install dependencies
424
+ npm install
425
+
426
+ # Run tests
427
+ npm test
428
+
429
+ # Build
430
+ npm run build
431
+ ```
432
+
433
+ ### Guidelines
434
+
435
+ - All changes must pass the existing test suite (`npm test`)
436
+ - New features must include corresponding tests
437
+ - Code must pass TypeScript strict mode
438
+ - Keep zero external runtime dependencies
439
+
440
+ ### Reporting Issues
441
+
442
+ Please [open an issue](https://github.com/denycode-dev/ip-ts/issues/new) with a minimal reproduction case.
443
+
444
+ ---
445
+
446
+ ## Migration from `ip`
447
+
448
+ **node-ip-ts** is designed to be a drop-in replacement. Simply swap your import:
449
+
450
+ ```diff
451
+ - const ip = require('ip');
452
+ + const ip = require('node-ip-ts');
453
+ ```
454
+
455
+ Or for TypeScript / ESM:
456
+
457
+ ```ts
458
+ import * as ip from 'node-ip-ts';
459
+ ```
460
+
461
+ All function names and behaviours are identical to the original library.
462
+
463
+ ---
464
+
465
+ ## License
466
+
467
+ [MIT](./LICENSE) © Deni Irawan Nugraha
468
+
469
+ ---
470
+
471
+ <div align="center">
472
+ <sub>If this library saved you time, consider giving it a ⭐ on GitHub.</sub>
473
+ </div>
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "node-ip-ts",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
4
4
  "author": "Deni Irawan Nugraha <deni.irawan40563@gmail.com>",
5
5
  "license": "MIT",
6
- "homepage": "https://github.com/denycode-dev/ip-ts",
6
+ "homepage": "https://node-ip-ts.vercel.app",
7
7
  "repository": {
8
8
  "type": "git",
9
9
  "url": "https://github.com/denycode-dev/ip-ts.git",