@ttmg/cli 0.3.8-beta.2 → 0.3.8-beta.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.
package/dist/index.js CHANGED
@@ -584,17 +584,17 @@ var hasRequiredBrowser;
584
584
  function requireBrowser () {
585
585
  if (hasRequiredBrowser) return browser.exports;
586
586
  hasRequiredBrowser = 1;
587
- (function (module, exports$1) {
587
+ (function (module, exports) {
588
588
  /**
589
589
  * This is the web browser implementation of `debug()`.
590
590
  */
591
591
 
592
- exports$1.formatArgs = formatArgs;
593
- exports$1.save = save;
594
- exports$1.load = load;
595
- exports$1.useColors = useColors;
596
- exports$1.storage = localstorage();
597
- exports$1.destroy = (() => {
592
+ exports.formatArgs = formatArgs;
593
+ exports.save = save;
594
+ exports.load = load;
595
+ exports.useColors = useColors;
596
+ exports.storage = localstorage();
597
+ exports.destroy = (() => {
598
598
  let warned = false;
599
599
 
600
600
  return () => {
@@ -609,7 +609,7 @@ function requireBrowser () {
609
609
  * Colors.
610
610
  */
611
611
 
612
- exports$1.colors = [
612
+ exports.colors = [
613
613
  '#0000CC',
614
614
  '#0000FF',
615
615
  '#0033CC',
@@ -774,7 +774,7 @@ function requireBrowser () {
774
774
  *
775
775
  * @api public
776
776
  */
777
- exports$1.log = console.debug || console.log || (() => {});
777
+ exports.log = console.debug || console.log || (() => {});
778
778
 
779
779
  /**
780
780
  * Save `namespaces`.
@@ -785,9 +785,9 @@ function requireBrowser () {
785
785
  function save(namespaces) {
786
786
  try {
787
787
  if (namespaces) {
788
- exports$1.storage.setItem('debug', namespaces);
788
+ exports.storage.setItem('debug', namespaces);
789
789
  } else {
790
- exports$1.storage.removeItem('debug');
790
+ exports.storage.removeItem('debug');
791
791
  }
792
792
  } catch (error) {
793
793
  // Swallow
@@ -804,7 +804,7 @@ function requireBrowser () {
804
804
  function load() {
805
805
  let r;
806
806
  try {
807
- r = exports$1.storage.getItem('debug') || exports$1.storage.getItem('DEBUG') ;
807
+ r = exports.storage.getItem('debug') || exports.storage.getItem('DEBUG') ;
808
808
  } catch (error) {
809
809
  // Swallow
810
810
  // XXX (@Qix-) should we be logging these?
@@ -840,7 +840,7 @@ function requireBrowser () {
840
840
  }
841
841
  }
842
842
 
843
- module.exports = requireCommon$1()(exports$1);
843
+ module.exports = requireCommon$1()(exports);
844
844
 
845
845
  const {formatters} = module.exports;
846
846
 
@@ -1029,7 +1029,7 @@ var hasRequiredNode;
1029
1029
  function requireNode () {
1030
1030
  if (hasRequiredNode) return node.exports;
1031
1031
  hasRequiredNode = 1;
1032
- (function (module, exports$1) {
1032
+ (function (module, exports) {
1033
1033
  const tty = require$$1;
1034
1034
  const util = require$$1$1;
1035
1035
 
@@ -1037,13 +1037,13 @@ function requireNode () {
1037
1037
  * This is the Node.js implementation of `debug()`.
1038
1038
  */
1039
1039
 
1040
- exports$1.init = init;
1041
- exports$1.log = log;
1042
- exports$1.formatArgs = formatArgs;
1043
- exports$1.save = save;
1044
- exports$1.load = load;
1045
- exports$1.useColors = useColors;
1046
- exports$1.destroy = util.deprecate(
1040
+ exports.init = init;
1041
+ exports.log = log;
1042
+ exports.formatArgs = formatArgs;
1043
+ exports.save = save;
1044
+ exports.load = load;
1045
+ exports.useColors = useColors;
1046
+ exports.destroy = util.deprecate(
1047
1047
  () => {},
1048
1048
  'Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`.'
1049
1049
  );
@@ -1052,7 +1052,7 @@ function requireNode () {
1052
1052
  * Colors.
1053
1053
  */
1054
1054
 
1055
- exports$1.colors = [6, 2, 3, 4, 5, 1];
1055
+ exports.colors = [6, 2, 3, 4, 5, 1];
1056
1056
 
1057
1057
  try {
1058
1058
  // Optional dependency (as in, doesn't need to be installed, NOT like optionalDependencies in package.json)
@@ -1060,7 +1060,7 @@ function requireNode () {
1060
1060
  const supportsColor = requireSupportsColor();
1061
1061
 
1062
1062
  if (supportsColor && (supportsColor.stderr || supportsColor).level >= 2) {
1063
- exports$1.colors = [
1063
+ exports.colors = [
1064
1064
  20,
1065
1065
  21,
1066
1066
  26,
@@ -1149,7 +1149,7 @@ function requireNode () {
1149
1149
  * $ DEBUG_COLORS=no DEBUG_DEPTH=10 DEBUG_SHOW_HIDDEN=enabled node script.js
1150
1150
  */
1151
1151
 
1152
- exports$1.inspectOpts = Object.keys(process.env).filter(key => {
1152
+ exports.inspectOpts = Object.keys(process.env).filter(key => {
1153
1153
  return /^debug_/i.test(key);
1154
1154
  }).reduce((obj, key) => {
1155
1155
  // Camel-case
@@ -1181,8 +1181,8 @@ function requireNode () {
1181
1181
  */
1182
1182
 
1183
1183
  function useColors() {
1184
- return 'colors' in exports$1.inspectOpts ?
1185
- Boolean(exports$1.inspectOpts.colors) :
1184
+ return 'colors' in exports.inspectOpts ?
1185
+ Boolean(exports.inspectOpts.colors) :
1186
1186
  tty.isatty(process.stderr.fd);
1187
1187
  }
1188
1188
 
@@ -1208,7 +1208,7 @@ function requireNode () {
1208
1208
  }
1209
1209
 
1210
1210
  function getDate() {
1211
- if (exports$1.inspectOpts.hideDate) {
1211
+ if (exports.inspectOpts.hideDate) {
1212
1212
  return '';
1213
1213
  }
1214
1214
  return new Date().toISOString() + ' ';
@@ -1219,7 +1219,7 @@ function requireNode () {
1219
1219
  */
1220
1220
 
1221
1221
  function log(...args) {
1222
- return process.stderr.write(util.formatWithOptions(exports$1.inspectOpts, ...args) + '\n');
1222
+ return process.stderr.write(util.formatWithOptions(exports.inspectOpts, ...args) + '\n');
1223
1223
  }
1224
1224
 
1225
1225
  /**
@@ -1259,13 +1259,13 @@ function requireNode () {
1259
1259
  function init(debug) {
1260
1260
  debug.inspectOpts = {};
1261
1261
 
1262
- const keys = Object.keys(exports$1.inspectOpts);
1262
+ const keys = Object.keys(exports.inspectOpts);
1263
1263
  for (let i = 0; i < keys.length; i++) {
1264
- debug.inspectOpts[keys[i]] = exports$1.inspectOpts[keys[i]];
1264
+ debug.inspectOpts[keys[i]] = exports.inspectOpts[keys[i]];
1265
1265
  }
1266
1266
  }
1267
1267
 
1268
- module.exports = requireCommon$1()(exports$1);
1268
+ module.exports = requireCommon$1()(exports);
1269
1269
 
1270
1270
  const {formatters} = module.exports;
1271
1271
 
@@ -3354,6 +3354,27 @@ var ipv4 = {};
3354
3354
 
3355
3355
  var common = {};
3356
3356
 
3357
+ var addressError = {};
3358
+
3359
+ var hasRequiredAddressError;
3360
+
3361
+ function requireAddressError () {
3362
+ if (hasRequiredAddressError) return addressError;
3363
+ hasRequiredAddressError = 1;
3364
+ Object.defineProperty(addressError, "__esModule", { value: true });
3365
+ addressError.AddressError = void 0;
3366
+ class AddressError extends Error {
3367
+ constructor(message, parseMessage) {
3368
+ super(message);
3369
+ this.name = 'AddressError';
3370
+ this.parseMessage = parseMessage;
3371
+ }
3372
+ }
3373
+ addressError.AddressError = AddressError;
3374
+
3375
+ return addressError;
3376
+ }
3377
+
3357
3378
  var hasRequiredCommon;
3358
3379
 
3359
3380
  function requireCommon () {
@@ -3362,9 +3383,11 @@ function requireCommon () {
3362
3383
  Object.defineProperty(common, "__esModule", { value: true });
3363
3384
  common.isInSubnet = isInSubnet;
3364
3385
  common.isCorrect = isCorrect;
3386
+ common.prefixLengthFromMask = prefixLengthFromMask;
3365
3387
  common.numberToPaddedHex = numberToPaddedHex;
3366
3388
  common.stringToPaddedHex = stringToPaddedHex;
3367
3389
  common.testBit = testBit;
3390
+ const address_error_1 = /*@__PURE__*/ requireAddressError();
3368
3391
  function isInSubnet(address) {
3369
3392
  if (this.subnetMask < address.subnetMask) {
3370
3393
  return false;
@@ -3385,6 +3408,25 @@ function requireCommon () {
3385
3408
  return this.parsedSubnet === String(this.subnetMask);
3386
3409
  };
3387
3410
  }
3411
+ /**
3412
+ * Returns the prefix length (number of leading 1 bits) of a contiguous
3413
+ * subnet mask. Throws `AddressError` if the mask is non-contiguous (e.g.
3414
+ * `255.0.255.0`).
3415
+ */
3416
+ function prefixLengthFromMask(value, totalBits) {
3417
+ const binary = value.toString(2).padStart(totalBits, '0');
3418
+ if (binary.length > totalBits) {
3419
+ throw new address_error_1.AddressError('Invalid subnet mask.');
3420
+ }
3421
+ const firstZero = binary.indexOf('0');
3422
+ if (firstZero === -1) {
3423
+ return totalBits;
3424
+ }
3425
+ if (binary.slice(firstZero).includes('1')) {
3426
+ throw new address_error_1.AddressError('Invalid subnet mask.');
3427
+ }
3428
+ return firstZero;
3429
+ }
3388
3430
  function numberToPaddedHex(number) {
3389
3431
  return number.toString(16).padStart(2, '0');
3390
3432
  }
@@ -3424,27 +3466,6 @@ function requireConstants$1 () {
3424
3466
  return constants$1;
3425
3467
  }
3426
3468
 
3427
- var addressError = {};
3428
-
3429
- var hasRequiredAddressError;
3430
-
3431
- function requireAddressError () {
3432
- if (hasRequiredAddressError) return addressError;
3433
- hasRequiredAddressError = 1;
3434
- Object.defineProperty(addressError, "__esModule", { value: true });
3435
- addressError.AddressError = void 0;
3436
- class AddressError extends Error {
3437
- constructor(message, parseMessage) {
3438
- super(message);
3439
- this.name = 'AddressError';
3440
- this.parseMessage = parseMessage;
3441
- }
3442
- }
3443
- addressError.AddressError = AddressError;
3444
-
3445
- return addressError;
3446
- }
3447
-
3448
3469
  var hasRequiredIpv4;
3449
3470
 
3450
3471
  function requireIpv4 () {
@@ -3476,12 +3497,12 @@ function requireIpv4 () {
3476
3497
  };
3477
3498
  Object.defineProperty(ipv4, "__esModule", { value: true });
3478
3499
  ipv4.Address4 = void 0;
3479
- const common = __importStar(requireCommon());
3480
- const constants = __importStar(requireConstants$1());
3481
- const address_error_1 = requireAddressError();
3500
+ const common = __importStar(/*@__PURE__*/ requireCommon());
3501
+ const constants = __importStar(/*@__PURE__*/ requireConstants$1());
3502
+ const address_error_1 = /*@__PURE__*/ requireAddressError();
3503
+ const isCorrect4 = common.isCorrect(constants.BITS);
3482
3504
  /**
3483
3505
  * Represents an IPv4 address
3484
- * @class Address4
3485
3506
  * @param {string} address - An IPv4 address string
3486
3507
  */
3487
3508
  class Address4 {
@@ -3494,15 +3515,11 @@ function requireIpv4 () {
3494
3515
  this.v4 = true;
3495
3516
  /**
3496
3517
  * Returns true if the address is correct, false otherwise
3497
- * @memberof Address4
3498
- * @instance
3499
3518
  * @returns {Boolean}
3500
3519
  */
3501
- this.isCorrect = common.isCorrect(constants.BITS);
3520
+ this.isCorrect = isCorrect4;
3502
3521
  /**
3503
3522
  * Returns true if the given address is in the subnet of the current address
3504
- * @memberof Address4
3505
- * @instance
3506
3523
  * @returns {boolean}
3507
3524
  */
3508
3525
  this.isInSubnet = common.isInSubnet;
@@ -3520,6 +3537,13 @@ function requireIpv4 () {
3520
3537
  this.addressMinusSuffix = address;
3521
3538
  this.parsedAddress = this.parse(address);
3522
3539
  }
3540
+ /**
3541
+ * Returns true if the given string is a valid IPv4 address (with optional
3542
+ * CIDR subnet), false otherwise. Host bits in the subnet portion are
3543
+ * allowed (e.g. `192.168.1.5/24` is valid); for strict network-address
3544
+ * validation compare `correctForm()` to `startAddress().correctForm()`,
3545
+ * or use `networkForm()`.
3546
+ */
3523
3547
  static isValid(address) {
3524
3548
  try {
3525
3549
  // eslint-disable-next-line no-new
@@ -3530,8 +3554,11 @@ function requireIpv4 () {
3530
3554
  return false;
3531
3555
  }
3532
3556
  }
3533
- /*
3534
- * Parses a v4 address
3557
+ /**
3558
+ * Parses an IPv4 address string into its four octet groups and stores the
3559
+ * result on `this.parsedAddress`. Called automatically by the constructor;
3560
+ * you typically don't need to call it directly. Throws `AddressError` if
3561
+ * the input is not a valid IPv4 address.
3535
3562
  */
3536
3563
  parse(address) {
3537
3564
  const groups = address.split('.');
@@ -3541,45 +3568,110 @@ function requireIpv4 () {
3541
3568
  return groups;
3542
3569
  }
3543
3570
  /**
3544
- * Returns the correct form of an address
3545
- * @memberof Address4
3546
- * @instance
3547
- * @returns {String}
3571
+ * Returns the address in correct form: octets joined with `.` and any
3572
+ * leading zeros stripped (e.g. `192.168.1.1`). For IPv4 this matches the
3573
+ * canonical dotted-decimal representation.
3548
3574
  */
3549
3575
  correctForm() {
3550
3576
  return this.parsedAddress.map((part) => parseInt(part, 10)).join('.');
3551
3577
  }
3552
3578
  /**
3553
- * Converts a hex string to an IPv4 address object
3554
- * @memberof Address4
3555
- * @static
3579
+ * Construct an `Address4` from an address and a dotted-decimal subnet
3580
+ * mask given as separate strings (e.g. as returned by Node's
3581
+ * `os.networkInterfaces()`). Throws `AddressError` if the mask is
3582
+ * non-contiguous (e.g. `255.0.255.0`).
3583
+ * @example
3584
+ * var address = Address4.fromAddressAndMask('192.168.1.1', '255.255.255.0');
3585
+ * address.subnetMask; // 24
3586
+ */
3587
+ static fromAddressAndMask(address, mask) {
3588
+ const bits = common.prefixLengthFromMask(new Address4(mask).bigInt(), constants.BITS);
3589
+ return new Address4(`${address}/${bits}`);
3590
+ }
3591
+ /**
3592
+ * Construct an `Address4` from an address and a Cisco-style wildcard mask
3593
+ * given as separate strings (e.g. `0.0.0.255` for a `/24`). The wildcard
3594
+ * mask is the bitwise inverse of the subnet mask. Throws `AddressError`
3595
+ * if the mask is non-contiguous (e.g. `0.255.0.255`).
3596
+ * @example
3597
+ * var address = Address4.fromAddressAndWildcardMask('10.0.0.1', '0.0.0.255');
3598
+ * address.subnetMask; // 24
3599
+ */
3600
+ static fromAddressAndWildcardMask(address, wildcardMask) {
3601
+ const wildcard = new Address4(wildcardMask).bigInt();
3602
+ const allOnes = (BigInt(1) << BigInt(constants.BITS)) - BigInt(1);
3603
+ // eslint-disable-next-line no-bitwise
3604
+ const mask = wildcard ^ allOnes;
3605
+ const bits = common.prefixLengthFromMask(mask, constants.BITS);
3606
+ return new Address4(`${address}/${bits}`);
3607
+ }
3608
+ /**
3609
+ * Construct an `Address4` from a wildcard pattern with trailing `*`
3610
+ * octets. The number of trailing wildcards determines the prefix
3611
+ * length: each `*` represents 8 bits.
3612
+ *
3613
+ * Only trailing whole-octet wildcards are supported. Partial-octet
3614
+ * wildcards (e.g. `192.168.0.1*`) and interior wildcards (e.g.
3615
+ * `192.*.0.1`) throw `AddressError`.
3616
+ * @example
3617
+ * Address4.fromWildcard('192.168.0.*').subnet; // '/24'
3618
+ * Address4.fromWildcard('192.168.*.*').subnet; // '/16'
3619
+ * Address4.fromWildcard('*.*.*.*').subnet; // '/0'
3620
+ */
3621
+ static fromWildcard(input) {
3622
+ const groups = input.split('.');
3623
+ if (groups.length !== constants.GROUPS) {
3624
+ throw new address_error_1.AddressError('Wildcard pattern must have 4 octets');
3625
+ }
3626
+ let firstWildcard = -1;
3627
+ for (let i = 0; i < groups.length; i++) {
3628
+ if (groups[i] === '*') {
3629
+ if (firstWildcard === -1) {
3630
+ firstWildcard = i;
3631
+ }
3632
+ }
3633
+ else if (firstWildcard !== -1) {
3634
+ throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing octets (e.g. `192.168.0.*`)');
3635
+ }
3636
+ }
3637
+ const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
3638
+ const replaced = groups.map((g) => (g === '*' ? '0' : g));
3639
+ const subnetBits = constants.BITS - trailing * 8;
3640
+ return new Address4(`${replaced.join('.')}/${subnetBits}`);
3641
+ }
3642
+ /**
3643
+ * Converts a hex string to an IPv4 address object. Accepts 8 hex digits
3644
+ * with optional `:` separators (e.g. `'7f000001'` or `'7f:00:00:01'`).
3645
+ * Throws `AddressError` for any other length or for non-hex characters.
3556
3646
  * @param {string} hex - a hex string to convert
3557
3647
  * @returns {Address4}
3558
3648
  */
3559
3649
  static fromHex(hex) {
3560
- const padded = hex.replace(/:/g, '').padStart(8, '0');
3650
+ const stripped = hex.replace(/:/g, '');
3651
+ if (!/^[0-9a-fA-F]{8}$/.test(stripped)) {
3652
+ throw new address_error_1.AddressError('IPv4 hex must be exactly 8 hex digits');
3653
+ }
3561
3654
  const groups = [];
3562
- let i;
3563
- for (i = 0; i < 8; i += 2) {
3564
- const h = padded.slice(i, i + 2);
3565
- groups.push(parseInt(h, 16));
3655
+ for (let i = 0; i < 8; i += 2) {
3656
+ groups.push(parseInt(stripped.slice(i, i + 2), 16));
3566
3657
  }
3567
3658
  return new Address4(groups.join('.'));
3568
3659
  }
3569
3660
  /**
3570
- * Converts an integer into a IPv4 address object
3571
- * @memberof Address4
3572
- * @static
3661
+ * Converts an integer into a IPv4 address object. The integer must be a
3662
+ * non-negative safe integer in the range `[0, 2**32 - 1]`; otherwise
3663
+ * `AddressError` is thrown.
3573
3664
  * @param {integer} integer - a number to convert
3574
3665
  * @returns {Address4}
3575
3666
  */
3576
3667
  static fromInteger(integer) {
3577
- return Address4.fromHex(integer.toString(16));
3668
+ if (!Number.isInteger(integer) || integer < 0 || integer > 0xffffffff) {
3669
+ throw new address_error_1.AddressError('IPv4 integer must be in the range 0 to 2**32 - 1');
3670
+ }
3671
+ return Address4.fromHex(integer.toString(16).padStart(8, '0'));
3578
3672
  }
3579
3673
  /**
3580
3674
  * Return an address from in-addr.arpa form
3581
- * @memberof Address4
3582
- * @static
3583
3675
  * @param {string} arpaFormAddress - an 'in-addr.arpa' form ipv4 address
3584
3676
  * @returns {Adress4}
3585
3677
  * @example
@@ -3594,17 +3686,15 @@ function requireIpv4 () {
3594
3686
  }
3595
3687
  /**
3596
3688
  * Converts an IPv4 address object to a hex string
3597
- * @memberof Address4
3598
- * @instance
3599
3689
  * @returns {String}
3600
3690
  */
3601
3691
  toHex() {
3602
3692
  return this.parsedAddress.map((part) => common.stringToPaddedHex(part)).join(':');
3603
3693
  }
3604
3694
  /**
3605
- * Converts an IPv4 address object to an array of bytes
3606
- * @memberof Address4
3607
- * @instance
3695
+ * Converts an IPv4 address object to an array of bytes.
3696
+ *
3697
+ * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toArray())`.
3608
3698
  * @returns {Array}
3609
3699
  */
3610
3700
  toArray() {
@@ -3612,8 +3702,6 @@ function requireIpv4 () {
3612
3702
  }
3613
3703
  /**
3614
3704
  * Converts an IPv4 address object to an IPv6 address group
3615
- * @memberof Address4
3616
- * @instance
3617
3705
  * @returns {String}
3618
3706
  */
3619
3707
  toGroup6() {
@@ -3626,8 +3714,6 @@ function requireIpv4 () {
3626
3714
  }
3627
3715
  /**
3628
3716
  * Returns the address as a `bigint`
3629
- * @memberof Address4
3630
- * @instance
3631
3717
  * @returns {bigint}
3632
3718
  */
3633
3719
  bigInt() {
@@ -3635,8 +3721,6 @@ function requireIpv4 () {
3635
3721
  }
3636
3722
  /**
3637
3723
  * Helper function getting start address.
3638
- * @memberof Address4
3639
- * @instance
3640
3724
  * @returns {bigint}
3641
3725
  */
3642
3726
  _startAddress() {
@@ -3645,8 +3729,6 @@ function requireIpv4 () {
3645
3729
  /**
3646
3730
  * The first address in the range given by this address' subnet.
3647
3731
  * Often referred to as the Network Address.
3648
- * @memberof Address4
3649
- * @instance
3650
3732
  * @returns {Address4}
3651
3733
  */
3652
3734
  startAddress() {
@@ -3655,8 +3737,6 @@ function requireIpv4 () {
3655
3737
  /**
3656
3738
  * The first host address in the range given by this address's subnet ie
3657
3739
  * the first address after the Network Address
3658
- * @memberof Address4
3659
- * @instance
3660
3740
  * @returns {Address4}
3661
3741
  */
3662
3742
  startAddressExclusive() {
@@ -3665,8 +3745,6 @@ function requireIpv4 () {
3665
3745
  }
3666
3746
  /**
3667
3747
  * Helper function getting end address.
3668
- * @memberof Address4
3669
- * @instance
3670
3748
  * @returns {bigint}
3671
3749
  */
3672
3750
  _endAddress() {
@@ -3675,8 +3753,6 @@ function requireIpv4 () {
3675
3753
  /**
3676
3754
  * The last address in the range given by this address' subnet
3677
3755
  * Often referred to as the Broadcast
3678
- * @memberof Address4
3679
- * @instance
3680
3756
  * @returns {Address4}
3681
3757
  */
3682
3758
  endAddress() {
@@ -3685,8 +3761,6 @@ function requireIpv4 () {
3685
3761
  /**
3686
3762
  * The last host address in the range given by this address's subnet ie
3687
3763
  * the last address prior to the Broadcast Address
3688
- * @memberof Address4
3689
- * @instance
3690
3764
  * @returns {Address4}
3691
3765
  */
3692
3766
  endAddressExclusive() {
@@ -3694,19 +3768,47 @@ function requireIpv4 () {
3694
3768
  return Address4.fromBigInt(this._endAddress() - adjust);
3695
3769
  }
3696
3770
  /**
3697
- * Converts a BigInt to a v4 address object
3698
- * @memberof Address4
3699
- * @static
3771
+ * The dotted-decimal form of the subnet mask, e.g. `255.255.240.0` for
3772
+ * a `/20`. Returns an `Address4`; call `.correctForm()` for the string.
3773
+ * @returns {Address4}
3774
+ */
3775
+ subnetMaskAddress() {
3776
+ return Address4.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants.BITS - this.subnetMask)}`));
3777
+ }
3778
+ /**
3779
+ * The Cisco-style wildcard mask, e.g. `0.0.0.255` for a `/24`. This is
3780
+ * the bitwise inverse of `subnetMaskAddress()`. Returns an `Address4`;
3781
+ * call `.correctForm()` for the string.
3782
+ * @returns {Address4}
3783
+ */
3784
+ wildcardMask() {
3785
+ return Address4.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants.BITS - this.subnetMask)}`));
3786
+ }
3787
+ /**
3788
+ * The network address in CIDR string form, e.g. `192.168.1.0/24` for
3789
+ * `192.168.1.5/24`. For an address with no explicit subnet the prefix is
3790
+ * `/32`, e.g. `networkForm()` on `192.168.1.5` returns `192.168.1.5/32`.
3791
+ * @returns {string}
3792
+ */
3793
+ networkForm() {
3794
+ return `${this.startAddress().correctForm()}/${this.subnetMask}`;
3795
+ }
3796
+ /**
3797
+ * Converts a BigInt to a v4 address object. The value must be in the
3798
+ * range `[0, 2**32 - 1]`; otherwise `AddressError` is thrown.
3700
3799
  * @param {bigint} bigInt - a BigInt to convert
3701
3800
  * @returns {Address4}
3702
3801
  */
3703
3802
  static fromBigInt(bigInt) {
3704
- return Address4.fromHex(bigInt.toString(16));
3803
+ if (bigInt < 0n || bigInt > 0xffffffffn) {
3804
+ throw new address_error_1.AddressError('IPv4 BigInt must be in the range 0 to 2**32 - 1');
3805
+ }
3806
+ return Address4.fromHex(bigInt.toString(16).padStart(8, '0'));
3705
3807
  }
3706
3808
  /**
3707
- * Convert a byte array to an Address4 object
3708
- * @memberof Address4
3709
- * @static
3809
+ * Convert a byte array to an Address4 object.
3810
+ *
3811
+ * To convert from a Node.js `Buffer`, spread it: `Address4.fromByteArray([...buf])`.
3710
3812
  * @param {Array<number>} bytes - an array of 4 bytes (0-255)
3711
3813
  * @returns {Address4}
3712
3814
  */
@@ -3724,8 +3826,6 @@ function requireIpv4 () {
3724
3826
  }
3725
3827
  /**
3726
3828
  * Convert an unsigned byte array to an Address4 object
3727
- * @memberof Address4
3728
- * @static
3729
3829
  * @param {Array<number>} bytes - an array of 4 unsigned bytes (0-255)
3730
3830
  * @returns {Address4}
3731
3831
  */
@@ -3739,8 +3839,6 @@ function requireIpv4 () {
3739
3839
  /**
3740
3840
  * Returns the first n bits of the address, defaulting to the
3741
3841
  * subnet mask
3742
- * @memberof Address4
3743
- * @instance
3744
3842
  * @returns {String}
3745
3843
  */
3746
3844
  mask(mask) {
@@ -3751,8 +3849,6 @@ function requireIpv4 () {
3751
3849
  }
3752
3850
  /**
3753
3851
  * Returns the bits in the given range as a base-2 string
3754
- * @memberof Address4
3755
- * @instance
3756
3852
  * @returns {string}
3757
3853
  */
3758
3854
  getBitsBase2(start, end) {
@@ -3760,10 +3856,8 @@ function requireIpv4 () {
3760
3856
  }
3761
3857
  /**
3762
3858
  * Return the reversed ip6.arpa form of the address
3763
- * @memberof Address4
3764
3859
  * @param {Object} options
3765
3860
  * @param {boolean} options.omitSuffix - omit the "in-addr.arpa" suffix
3766
- * @instance
3767
3861
  * @returns {String}
3768
3862
  */
3769
3863
  reverseForm(options) {
@@ -3778,21 +3872,62 @@ function requireIpv4 () {
3778
3872
  }
3779
3873
  /**
3780
3874
  * Returns true if the given address is a multicast address
3781
- * @memberof Address4
3782
- * @instance
3783
3875
  * @returns {boolean}
3784
3876
  */
3785
3877
  isMulticast() {
3786
- return this.isInSubnet(new Address4('224.0.0.0/4'));
3878
+ return this.isInSubnet(MULTICAST_V4);
3879
+ }
3880
+ /**
3881
+ * Returns true if the address is in one of the [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private address ranges (`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`).
3882
+ * @returns {boolean}
3883
+ */
3884
+ isPrivate() {
3885
+ return PRIVATE_V4.some((subnet) => this.isInSubnet(subnet));
3886
+ }
3887
+ /**
3888
+ * Returns true if the address is in the loopback range `127.0.0.0/8` ([RFC 1122](https://datatracker.ietf.org/doc/html/rfc1122)).
3889
+ * @returns {boolean}
3890
+ */
3891
+ isLoopback() {
3892
+ return this.isInSubnet(LOOPBACK_V4);
3893
+ }
3894
+ /**
3895
+ * Returns true if the address is in the link-local range `169.254.0.0/16` ([RFC 3927](https://datatracker.ietf.org/doc/html/rfc3927)).
3896
+ * @returns {boolean}
3897
+ */
3898
+ isLinkLocal() {
3899
+ return this.isInSubnet(LINK_LOCAL_V4);
3900
+ }
3901
+ /**
3902
+ * Returns true if the address is the unspecified address `0.0.0.0`.
3903
+ * @returns {boolean}
3904
+ */
3905
+ isUnspecified() {
3906
+ return this.isInSubnet(UNSPECIFIED_V4);
3907
+ }
3908
+ /**
3909
+ * Returns true if the address is the limited broadcast address `255.255.255.255` ([RFC 919](https://datatracker.ietf.org/doc/html/rfc919)).
3910
+ * @returns {boolean}
3911
+ */
3912
+ isBroadcast() {
3913
+ return this.isInSubnet(BROADCAST_V4);
3914
+ }
3915
+ /**
3916
+ * Returns true if the address is in the carrier-grade NAT range `100.64.0.0/10` ([RFC 6598](https://datatracker.ietf.org/doc/html/rfc6598)).
3917
+ * @returns {boolean}
3918
+ */
3919
+ isCGNAT() {
3920
+ return this.isInSubnet(CGNAT_V4);
3787
3921
  }
3788
3922
  /**
3789
3923
  * Returns a zero-padded base-2 string representation of the address
3790
- * @memberof Address4
3791
- * @instance
3792
3924
  * @returns {string}
3793
3925
  */
3794
3926
  binaryZeroPad() {
3795
- return this.bigInt().toString(2).padStart(constants.BITS, '0');
3927
+ if (this._binaryZeroPad === undefined) {
3928
+ this._binaryZeroPad = this.bigInt().toString(2).padStart(constants.BITS, '0');
3929
+ }
3930
+ return this._binaryZeroPad;
3796
3931
  }
3797
3932
  /**
3798
3933
  * Groups an IPv4 address for inclusion at the end of an IPv6 address
@@ -3808,6 +3943,17 @@ function requireIpv4 () {
3808
3943
  }
3809
3944
  }
3810
3945
  ipv4.Address4 = Address4;
3946
+ const MULTICAST_V4 = new Address4('224.0.0.0/4');
3947
+ const PRIVATE_V4 = [
3948
+ new Address4('10.0.0.0/8'),
3949
+ new Address4('172.16.0.0/12'),
3950
+ new Address4('192.168.0.0/16'),
3951
+ ];
3952
+ const LOOPBACK_V4 = new Address4('127.0.0.0/8');
3953
+ const LINK_LOCAL_V4 = new Address4('169.254.0.0/16');
3954
+ const UNSPECIFIED_V4 = new Address4('0.0.0.0/32');
3955
+ const BROADCAST_V4 = new Address4('255.255.255.255/32');
3956
+ const CGNAT_V4 = new Address4('100.64.0.0/10');
3811
3957
 
3812
3958
  return ipv4;
3813
3959
  }
@@ -3868,6 +4014,11 @@ function requireConstants () {
3868
4014
  '::1/128': 'Loopback',
3869
4015
  'ff00::/8': 'Multicast',
3870
4016
  'fe80::/10': 'Link-local unicast',
4017
+ 'fc00::/7': 'Unique local',
4018
+ '2002::/16': '6to4',
4019
+ '2001:db8::/32': 'Documentation',
4020
+ '64:ff9b::/96': 'NAT64 (well-known)',
4021
+ '64:ff9b:1::/48': 'NAT64 (local-use)',
3871
4022
  };
3872
4023
  /**
3873
4024
  * A regular expression that matches bad characters in an IPv6 address
@@ -3907,15 +4058,24 @@ function requireHelpers$1 () {
3907
4058
  if (hasRequiredHelpers$1) return helpers;
3908
4059
  hasRequiredHelpers$1 = 1;
3909
4060
  Object.defineProperty(helpers, "__esModule", { value: true });
4061
+ helpers.escapeHtml = escapeHtml;
3910
4062
  helpers.spanAllZeroes = spanAllZeroes;
3911
4063
  helpers.spanAll = spanAll;
3912
4064
  helpers.spanLeadingZeroes = spanLeadingZeroes;
3913
4065
  helpers.simpleGroup = simpleGroup;
4066
+ function escapeHtml(s) {
4067
+ return s
4068
+ .replace(/&/g, '&amp;')
4069
+ .replace(/</g, '&lt;')
4070
+ .replace(/>/g, '&gt;')
4071
+ .replace(/"/g, '&quot;')
4072
+ .replace(/'/g, '&#39;');
4073
+ }
3914
4074
  /**
3915
4075
  * @returns {String} the string with all zeroes contained in a <span>
3916
4076
  */
3917
4077
  function spanAllZeroes(s) {
3918
- return s.replace(/(0+)/g, '<span class="zero">$1</span>');
4078
+ return escapeHtml(s).replace(/(0+)/g, '<span class="zero">$1</span>');
3919
4079
  }
3920
4080
  /**
3921
4081
  * @returns {String} the string with each character contained in a <span>
@@ -3923,11 +4083,11 @@ function requireHelpers$1 () {
3923
4083
  function spanAll(s, offset = 0) {
3924
4084
  const letters = s.split('');
3925
4085
  return letters
3926
- .map((n, i) => `<span class="digit value-${n} position-${i + offset}">${spanAllZeroes(n)}</span>`)
4086
+ .map((n, i) => `<span class="digit value-${escapeHtml(n)} position-${i + offset}">${spanAllZeroes(n)}</span>`)
3927
4087
  .join('');
3928
4088
  }
3929
4089
  function spanLeadingZeroesSimple(group) {
3930
- return group.replace(/^(0+)/, '<span class="zero">$1</span>');
4090
+ return escapeHtml(group).replace(/^(0+)/, '<span class="zero">$1</span>');
3931
4091
  }
3932
4092
  /**
3933
4093
  * @returns {String} the string with leading zeroes contained in a <span>
@@ -3989,7 +4149,7 @@ function requireRegularExpressions () {
3989
4149
  regularExpressions.padGroup = padGroup;
3990
4150
  regularExpressions.simpleRegularExpression = simpleRegularExpression;
3991
4151
  regularExpressions.possibleElisions = possibleElisions;
3992
- const v6 = __importStar(requireConstants());
4152
+ const v6 = __importStar(/*@__PURE__*/ requireConstants());
3993
4153
  function groupPossibilities(possibilities) {
3994
4154
  return `(${possibilities.join('|')})`;
3995
4155
  }
@@ -4089,14 +4249,15 @@ function requireIpv6 () {
4089
4249
  };
4090
4250
  Object.defineProperty(ipv6, "__esModule", { value: true });
4091
4251
  ipv6.Address6 = void 0;
4092
- const common = __importStar(requireCommon());
4093
- const constants4 = __importStar(requireConstants$1());
4094
- const constants6 = __importStar(requireConstants());
4095
- const helpers = __importStar(requireHelpers$1());
4096
- const ipv4_1 = requireIpv4();
4097
- const regular_expressions_1 = requireRegularExpressions();
4098
- const address_error_1 = requireAddressError();
4099
- const common_1 = requireCommon();
4252
+ const common = __importStar(/*@__PURE__*/ requireCommon());
4253
+ const constants4 = __importStar(/*@__PURE__*/ requireConstants$1());
4254
+ const constants6 = __importStar(/*@__PURE__*/ requireConstants());
4255
+ const helpers = __importStar(/*@__PURE__*/ requireHelpers$1());
4256
+ const ipv4_1 = /*@__PURE__*/ requireIpv4();
4257
+ const regular_expressions_1 = /*@__PURE__*/ requireRegularExpressions();
4258
+ const address_error_1 = /*@__PURE__*/ requireAddressError();
4259
+ const common_1 = /*@__PURE__*/ requireCommon();
4260
+ const isCorrect6 = common.isCorrect(constants6.BITS);
4100
4261
  function assert(condition) {
4101
4262
  if (!condition) {
4102
4263
  throw new Error('Assertion failed.');
@@ -4140,7 +4301,6 @@ function requireIpv6 () {
4140
4301
  }
4141
4302
  /**
4142
4303
  * Represents an IPv6 address
4143
- * @class Address6
4144
4304
  * @param {string} address - An IPv6 address string
4145
4305
  * @param {number} [groups=8] - How many octets to parse
4146
4306
  * @example
@@ -4157,18 +4317,14 @@ function requireIpv6 () {
4157
4317
  // #region Attributes
4158
4318
  /**
4159
4319
  * Returns true if the given address is in the subnet of the current address
4160
- * @memberof Address6
4161
- * @instance
4162
4320
  * @returns {boolean}
4163
4321
  */
4164
4322
  this.isInSubnet = common.isInSubnet;
4165
4323
  /**
4166
4324
  * Returns true if the address is correct, false otherwise
4167
- * @memberof Address6
4168
- * @instance
4169
4325
  * @returns {boolean}
4170
4326
  */
4171
- this.isCorrect = common.isCorrect(constants6.BITS);
4327
+ this.isCorrect = isCorrect6;
4172
4328
  if (optionalGroups === undefined) {
4173
4329
  this.groups = constants6.GROUPS;
4174
4330
  }
@@ -4199,6 +4355,13 @@ function requireIpv6 () {
4199
4355
  this.addressMinusSuffix = address;
4200
4356
  this.parsedAddress = this.parse(this.addressMinusSuffix);
4201
4357
  }
4358
+ /**
4359
+ * Returns true if the given string is a valid IPv6 address (with optional
4360
+ * CIDR subnet and zone identifier), false otherwise. Host bits in the
4361
+ * subnet portion are allowed (e.g. `2001:db8::1/32` is valid); for strict
4362
+ * network-address validation compare `correctForm()` to
4363
+ * `startAddress().correctForm()`, or use `networkForm()`.
4364
+ */
4202
4365
  static isValid(address) {
4203
4366
  try {
4204
4367
  // eslint-disable-next-line no-new
@@ -4210,9 +4373,8 @@ function requireIpv6 () {
4210
4373
  }
4211
4374
  }
4212
4375
  /**
4213
- * Convert a BigInt to a v6 address object
4214
- * @memberof Address6
4215
- * @static
4376
+ * Convert a BigInt to a v6 address object. The value must be in the
4377
+ * range `[0, 2**128 - 1]`; otherwise `AddressError` is thrown.
4216
4378
  * @param {bigint} bigInt - a BigInt to convert
4217
4379
  * @returns {Address6}
4218
4380
  * @example
@@ -4221,19 +4383,21 @@ function requireIpv6 () {
4221
4383
  * address.correctForm(); // '::e8:d4a5:1000'
4222
4384
  */
4223
4385
  static fromBigInt(bigInt) {
4386
+ if (bigInt < 0n || bigInt > (1n << BigInt(constants6.BITS)) - 1n) {
4387
+ throw new address_error_1.AddressError('IPv6 BigInt must be in the range 0 to 2**128 - 1');
4388
+ }
4224
4389
  const hex = bigInt.toString(16).padStart(32, '0');
4225
4390
  const groups = [];
4226
- let i;
4227
- for (i = 0; i < constants6.GROUPS; i++) {
4391
+ for (let i = 0; i < constants6.GROUPS; i++) {
4228
4392
  groups.push(hex.slice(i * 4, (i + 1) * 4));
4229
4393
  }
4230
4394
  return new Address6(groups.join(':'));
4231
4395
  }
4232
4396
  /**
4233
- * Convert a URL (with optional port number) to an address object
4234
- * @memberof Address6
4235
- * @static
4236
- * @param {string} url - a URL with optional port number
4397
+ * Parse a URL (with optional bracketed host and port) into an address and
4398
+ * port. Returns either `{ address, port }` on success or
4399
+ * `{ error, address: null, port: null }` if the URL could not be parsed.
4400
+ * Ports are returned as numbers (or `null` if absent or out of range).
4237
4401
  * @example
4238
4402
  * var addressAndPort = Address6.fromURL('http://[ffff::]:8080/foo/');
4239
4403
  * addressAndPort.address.correctForm(); // 'ffff::'
@@ -4292,10 +4456,92 @@ function requireIpv6 () {
4292
4456
  port,
4293
4457
  };
4294
4458
  }
4459
+ /**
4460
+ * Construct an `Address6` from an address and a hex subnet mask given as
4461
+ * separate strings (e.g. as returned by Node's `os.networkInterfaces()`).
4462
+ * Throws `AddressError` if the mask is non-contiguous (e.g.
4463
+ * `ffff::ffff`).
4464
+ * @example
4465
+ * var address = Address6.fromAddressAndMask('fe80::1', 'ffff:ffff:ffff:ffff::');
4466
+ * address.subnetMask; // 64
4467
+ */
4468
+ static fromAddressAndMask(address, mask) {
4469
+ const bits = common.prefixLengthFromMask(new Address6(mask).bigInt(), constants6.BITS);
4470
+ return new Address6(`${address}/${bits}`);
4471
+ }
4472
+ /**
4473
+ * Construct an `Address6` from an address and a Cisco-style wildcard mask
4474
+ * given as separate strings (e.g. `::ffff:ffff:ffff:ffff` for a `/64`).
4475
+ * The wildcard mask is the bitwise inverse of the subnet mask. Throws
4476
+ * `AddressError` if the mask is non-contiguous.
4477
+ * @example
4478
+ * var address = Address6.fromAddressAndWildcardMask('fe80::1', '::ffff:ffff:ffff:ffff');
4479
+ * address.subnetMask; // 64
4480
+ */
4481
+ static fromAddressAndWildcardMask(address, wildcardMask) {
4482
+ const wildcard = new Address6(wildcardMask).bigInt();
4483
+ const allOnes = (BigInt(1) << BigInt(constants6.BITS)) - BigInt(1);
4484
+ // eslint-disable-next-line no-bitwise
4485
+ const mask = wildcard ^ allOnes;
4486
+ const bits = common.prefixLengthFromMask(mask, constants6.BITS);
4487
+ return new Address6(`${address}/${bits}`);
4488
+ }
4489
+ /**
4490
+ * Construct an `Address6` from a wildcard pattern with trailing `*`
4491
+ * groups. The number of trailing wildcards determines the prefix
4492
+ * length: each `*` represents 16 bits. `::` is expanded to zero groups
4493
+ * (not wildcards) before evaluating trailing wildcards.
4494
+ *
4495
+ * Only trailing whole-group wildcards are supported. Partial-group
4496
+ * wildcards (e.g. `2001:db8::0*`) and interior wildcards (e.g.
4497
+ * `*::1`) throw `AddressError`.
4498
+ * @example
4499
+ * Address6.fromWildcard('2001:db8:*:*:*:*:*:*').subnet; // '/32'
4500
+ * Address6.fromWildcard('2001:db8::*').subnet; // '/112'
4501
+ * Address6.fromWildcard('*:*:*:*:*:*:*:*').subnet; // '/0'
4502
+ */
4503
+ static fromWildcard(input) {
4504
+ if (input.includes('%') || input.includes('/')) {
4505
+ throw new address_error_1.AddressError('Wildcard pattern must not include a zone or CIDR suffix');
4506
+ }
4507
+ const halves = input.split('::');
4508
+ if (halves.length > 2) {
4509
+ throw new address_error_1.AddressError("Wildcard pattern cannot contain more than one '::'");
4510
+ }
4511
+ let groups;
4512
+ if (halves.length === 2) {
4513
+ const left = halves[0] === '' ? [] : halves[0].split(':');
4514
+ const right = halves[1] === '' ? [] : halves[1].split(':');
4515
+ const remaining = constants6.GROUPS - left.length - right.length;
4516
+ if (remaining < 1) {
4517
+ throw new address_error_1.AddressError("Wildcard pattern with '::' has too many groups");
4518
+ }
4519
+ groups = [...left, ...new Array(remaining).fill('0'), ...right];
4520
+ }
4521
+ else {
4522
+ groups = input.split(':');
4523
+ }
4524
+ if (groups.length !== constants6.GROUPS) {
4525
+ throw new address_error_1.AddressError('Wildcard pattern must have 8 groups');
4526
+ }
4527
+ let firstWildcard = -1;
4528
+ for (let i = 0; i < groups.length; i++) {
4529
+ if (groups[i] === '*') {
4530
+ if (firstWildcard === -1) {
4531
+ firstWildcard = i;
4532
+ }
4533
+ }
4534
+ else if (firstWildcard !== -1) {
4535
+ throw new address_error_1.AddressError('Wildcard `*` must only appear in trailing groups (e.g. `2001:db8:*:*:*:*:*:*`)');
4536
+ }
4537
+ }
4538
+ const trailing = firstWildcard === -1 ? 0 : groups.length - firstWildcard;
4539
+ const replaced = groups.map((g) => (g === '*' ? '0' : g));
4540
+ const subnetBits = constants6.BITS - trailing * 16;
4541
+ return new Address6(`${replaced.join(':')}/${subnetBits}`);
4542
+ }
4295
4543
  /**
4296
4544
  * Create an IPv6-mapped address given an IPv4 address
4297
- * @memberof Address6
4298
- * @static
4299
4545
  * @param {string} address - An IPv4 address string
4300
4546
  * @returns {Address6}
4301
4547
  * @example
@@ -4310,8 +4556,6 @@ function requireIpv6 () {
4310
4556
  }
4311
4557
  /**
4312
4558
  * Return an address from ip6.arpa form
4313
- * @memberof Address6
4314
- * @static
4315
4559
  * @param {string} arpaFormAddress - an 'ip6.arpa' form address
4316
4560
  * @returns {Adress6}
4317
4561
  * @example
@@ -4336,8 +4580,6 @@ function requireIpv6 () {
4336
4580
  }
4337
4581
  /**
4338
4582
  * Return the Microsoft UNC transcription of the address
4339
- * @memberof Address6
4340
- * @instance
4341
4583
  * @returns {String} the Microsoft UNC transcription of the address
4342
4584
  */
4343
4585
  microsoftTranscription() {
@@ -4345,8 +4587,6 @@ function requireIpv6 () {
4345
4587
  }
4346
4588
  /**
4347
4589
  * Return the first n bits of the address, defaulting to the subnet mask
4348
- * @memberof Address6
4349
- * @instance
4350
4590
  * @param {number} [mask=subnet] - the number of bits to mask
4351
4591
  * @returns {String} the first n bits of the address as a string
4352
4592
  */
@@ -4355,8 +4595,6 @@ function requireIpv6 () {
4355
4595
  }
4356
4596
  /**
4357
4597
  * Return the number of possible subnets of a given size in the address
4358
- * @memberof Address6
4359
- * @instance
4360
4598
  * @param {number} [subnetSize=128] - the subnet size
4361
4599
  * @returns {String}
4362
4600
  */
@@ -4372,8 +4610,6 @@ function requireIpv6 () {
4372
4610
  }
4373
4611
  /**
4374
4612
  * Helper function getting start address.
4375
- * @memberof Address6
4376
- * @instance
4377
4613
  * @returns {bigint}
4378
4614
  */
4379
4615
  _startAddress() {
@@ -4382,8 +4618,6 @@ function requireIpv6 () {
4382
4618
  /**
4383
4619
  * The first address in the range given by this address' subnet
4384
4620
  * Often referred to as the Network Address.
4385
- * @memberof Address6
4386
- * @instance
4387
4621
  * @returns {Address6}
4388
4622
  */
4389
4623
  startAddress() {
@@ -4392,8 +4626,6 @@ function requireIpv6 () {
4392
4626
  /**
4393
4627
  * The first host address in the range given by this address's subnet ie
4394
4628
  * the first address after the Network Address
4395
- * @memberof Address6
4396
- * @instance
4397
4629
  * @returns {Address6}
4398
4630
  */
4399
4631
  startAddressExclusive() {
@@ -4402,8 +4634,6 @@ function requireIpv6 () {
4402
4634
  }
4403
4635
  /**
4404
4636
  * Helper function getting end address.
4405
- * @memberof Address6
4406
- * @instance
4407
4637
  * @returns {bigint}
4408
4638
  */
4409
4639
  _endAddress() {
@@ -4412,8 +4642,6 @@ function requireIpv6 () {
4412
4642
  /**
4413
4643
  * The last address in the range given by this address' subnet
4414
4644
  * Often referred to as the Broadcast
4415
- * @memberof Address6
4416
- * @instance
4417
4645
  * @returns {Address6}
4418
4646
  */
4419
4647
  endAddress() {
@@ -4422,8 +4650,6 @@ function requireIpv6 () {
4422
4650
  /**
4423
4651
  * The last host address in the range given by this address's subnet ie
4424
4652
  * the last address prior to the Broadcast Address
4425
- * @memberof Address6
4426
- * @instance
4427
4653
  * @returns {Address6}
4428
4654
  */
4429
4655
  endAddressExclusive() {
@@ -4431,36 +4657,73 @@ function requireIpv6 () {
4431
4657
  return Address6.fromBigInt(this._endAddress() - adjust);
4432
4658
  }
4433
4659
  /**
4434
- * Return the scope of the address
4435
- * @memberof Address6
4436
- * @instance
4660
+ * The hex form of the subnet mask, e.g. `ffff:ffff:ffff:ffff::` for a
4661
+ * `/64`. Returns an `Address6`; call `.correctForm()` for the string.
4662
+ * @returns {Address6}
4663
+ */
4664
+ subnetMaskAddress() {
4665
+ return Address6.fromBigInt(BigInt(`0b${'1'.repeat(this.subnetMask)}${'0'.repeat(constants6.BITS - this.subnetMask)}`));
4666
+ }
4667
+ /**
4668
+ * The Cisco-style wildcard mask, e.g. `::ffff:ffff:ffff:ffff` for a
4669
+ * `/64`. This is the bitwise inverse of `subnetMaskAddress()`. Returns
4670
+ * an `Address6`; call `.correctForm()` for the string.
4671
+ * @returns {Address6}
4672
+ */
4673
+ wildcardMask() {
4674
+ return Address6.fromBigInt(BigInt(`0b${'0'.repeat(this.subnetMask)}${'1'.repeat(constants6.BITS - this.subnetMask)}`));
4675
+ }
4676
+ /**
4677
+ * The network address in CIDR string form, e.g. `2001:db8::/32` for
4678
+ * `2001:db8::1/32`. For an address with no explicit subnet the prefix
4679
+ * is `/128`, e.g. `networkForm()` on `2001:db8::1` returns
4680
+ * `2001:db8::1/128`.
4681
+ * @returns {string}
4682
+ */
4683
+ networkForm() {
4684
+ return `${this.startAddress().correctForm()}/${this.subnetMask}`;
4685
+ }
4686
+ /**
4687
+ * Return the scope of the address. The 4-bit scope field
4688
+ * ([RFC 4291 §2.7](https://datatracker.ietf.org/doc/html/rfc4291#section-2.7))
4689
+ * is only defined for multicast addresses; for unicast addresses the scope
4690
+ * is derived from the address type per
4691
+ * [RFC 4007 §6](https://datatracker.ietf.org/doc/html/rfc4007#section-6).
4437
4692
  * @returns {String}
4438
4693
  */
4439
4694
  getScope() {
4440
- let scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
4441
- if (this.getType() === 'Global unicast' && scope !== 'Link local') {
4442
- scope = 'Global';
4695
+ const type = this.getType();
4696
+ if (type === 'Multicast' || type.startsWith('Multicast ')) {
4697
+ const scope = constants6.SCOPES[parseInt(this.getBits(12, 16).toString(10), 10)];
4698
+ return scope || 'Unknown';
4443
4699
  }
4444
- return scope || 'Unknown';
4700
+ // RFC 4291 §2.5.3: the loopback address is treated as having Link-Local
4701
+ // scope. (Multicast scope 1, "Interface-Local", is a different concept
4702
+ // used only for loopback transmission of multicast.)
4703
+ if (type === 'Link-local unicast' || type === 'Loopback') {
4704
+ return 'Link local';
4705
+ }
4706
+ // RFC 4007 §6: the unspecified address has no scope.
4707
+ if (type === 'Unspecified') {
4708
+ return 'Unknown';
4709
+ }
4710
+ return 'Global';
4445
4711
  }
4446
4712
  /**
4447
4713
  * Return the type of the address
4448
- * @memberof Address6
4449
- * @instance
4450
4714
  * @returns {String}
4451
4715
  */
4452
4716
  getType() {
4453
- for (const subnet of Object.keys(constants6.TYPES)) {
4454
- if (this.isInSubnet(new Address6(subnet))) {
4455
- return constants6.TYPES[subnet];
4717
+ for (let i = 0; i < TYPE_SUBNETS.length; i++) {
4718
+ const entry = TYPE_SUBNETS[i];
4719
+ if (this.isInSubnet(entry[0])) {
4720
+ return entry[1];
4456
4721
  }
4457
4722
  }
4458
4723
  return 'Global unicast';
4459
4724
  }
4460
4725
  /**
4461
4726
  * Return the bits in the given range as a BigInt
4462
- * @memberof Address6
4463
- * @instance
4464
4727
  * @returns {bigint}
4465
4728
  */
4466
4729
  getBits(start, end) {
@@ -4468,8 +4731,6 @@ function requireIpv6 () {
4468
4731
  }
4469
4732
  /**
4470
4733
  * Return the bits in the given range as a base-2 string
4471
- * @memberof Address6
4472
- * @instance
4473
4734
  * @returns {String}
4474
4735
  */
4475
4736
  getBitsBase2(start, end) {
@@ -4477,8 +4738,6 @@ function requireIpv6 () {
4477
4738
  }
4478
4739
  /**
4479
4740
  * Return the bits in the given range as a base-16 string
4480
- * @memberof Address6
4481
- * @instance
4482
4741
  * @returns {String}
4483
4742
  */
4484
4743
  getBitsBase16(start, end) {
@@ -4492,8 +4751,6 @@ function requireIpv6 () {
4492
4751
  }
4493
4752
  /**
4494
4753
  * Return the bits that are set past the subnet mask length
4495
- * @memberof Address6
4496
- * @instance
4497
4754
  * @returns {String}
4498
4755
  */
4499
4756
  getBitsPastSubnet() {
@@ -4501,10 +4758,8 @@ function requireIpv6 () {
4501
4758
  }
4502
4759
  /**
4503
4760
  * Return the reversed ip6.arpa form of the address
4504
- * @memberof Address6
4505
4761
  * @param {Object} options
4506
4762
  * @param {boolean} options.omitSuffix - omit the "ip6.arpa" suffix
4507
- * @instance
4508
4763
  * @returns {String}
4509
4764
  */
4510
4765
  reverseForm(options) {
@@ -4530,10 +4785,10 @@ function requireIpv6 () {
4530
4785
  return 'ip6.arpa.';
4531
4786
  }
4532
4787
  /**
4533
- * Return the correct form of the address
4534
- * @memberof Address6
4535
- * @instance
4536
- * @returns {String}
4788
+ * Returns the address in correct form, per
4789
+ * [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952): leading zeros
4790
+ * stripped, the longest run of zero groups collapsed to `::`, and hex digits
4791
+ * lowercased (e.g. `2001:db8::1`). This is the recommended form for display.
4537
4792
  */
4538
4793
  correctForm() {
4539
4794
  let i;
@@ -4577,8 +4832,6 @@ function requireIpv6 () {
4577
4832
  }
4578
4833
  /**
4579
4834
  * Return a zero-padded base-2 string representation of the address
4580
- * @memberof Address6
4581
- * @instance
4582
4835
  * @returns {String}
4583
4836
  * @example
4584
4837
  * var address = new Address6('2001:4860:4001:803::1011');
@@ -4587,10 +4840,22 @@ function requireIpv6 () {
4587
4840
  * // 0000000000000000000000000000000000000000000000000001000000010001'
4588
4841
  */
4589
4842
  binaryZeroPad() {
4590
- return this.bigInt().toString(2).padStart(constants6.BITS, '0');
4843
+ if (this._binaryZeroPad === undefined) {
4844
+ this._binaryZeroPad = this.bigInt().toString(2).padStart(constants6.BITS, '0');
4845
+ }
4846
+ return this._binaryZeroPad;
4591
4847
  }
4848
+ /**
4849
+ * Parses a v4-in-v6 string (e.g. `::ffff:192.168.0.1`) by extracting the
4850
+ * trailing IPv4 address into `this.address4` / `this.parsedAddress4` and
4851
+ * returning the address with the v4 portion converted to two v6 groups.
4852
+ * Used internally by `parse()`.
4853
+ */
4592
4854
  // TODO: Improve the semantics of this helper function
4593
4855
  parse4in6(address) {
4856
+ if (address.indexOf('.') === -1) {
4857
+ return address;
4858
+ }
4594
4859
  const groups = address.split(':');
4595
4860
  const lastGroup = groups.slice(-1)[0];
4596
4861
  const address4 = lastGroup.match(constants4.RE_ADDRESS);
@@ -4599,7 +4864,12 @@ function requireIpv6 () {
4599
4864
  this.address4 = new ipv4_1.Address4(this.parsedAddress4);
4600
4865
  for (let i = 0; i < this.address4.groups; i++) {
4601
4866
  if (/^0[0-9]+/.test(this.address4.parsedAddress[i])) {
4602
- throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", address.replace(constants4.RE_ADDRESS, this.address4.parsedAddress.map(spanLeadingZeroes4).join('.')));
4867
+ // The prefix groups haven't been through the bad-character check
4868
+ // yet, so escape them before including in the error HTML.
4869
+ const highlighted = this.address4.parsedAddress.map(spanLeadingZeroes4).join('.');
4870
+ const prefix = groups.slice(0, -1).map(helpers.escapeHtml).join(':');
4871
+ const separator = groups.length > 1 ? ':' : '';
4872
+ throw new address_error_1.AddressError("IPv4 addresses can't have leading zeroes.", `${prefix}${separator}${highlighted}`);
4603
4873
  }
4604
4874
  }
4605
4875
  this.v4 = true;
@@ -4608,6 +4878,13 @@ function requireIpv6 () {
4608
4878
  }
4609
4879
  return address;
4610
4880
  }
4881
+ /**
4882
+ * Parses an IPv6 address string into its 8 hexadecimal groups (expanding
4883
+ * any `::` elision and any trailing v4-in-v6 portion) and stores the result
4884
+ * on `this.parsedAddress`. Called automatically by the constructor; you
4885
+ * typically don't need to call it directly. Throws `AddressError` if the
4886
+ * input is malformed.
4887
+ */
4611
4888
  // TODO: Make private?
4612
4889
  parse(address) {
4613
4890
  address = this.parse4in6(address);
@@ -4657,18 +4934,16 @@ function requireIpv6 () {
4657
4934
  return groups;
4658
4935
  }
4659
4936
  /**
4660
- * Return the canonical form of the address
4661
- * @memberof Address6
4662
- * @instance
4663
- * @returns {String}
4937
+ * Returns the canonical (fully expanded) form of the address: all 8 groups,
4938
+ * each padded to 4 hex digits, with no `::` collapsing
4939
+ * (e.g. `2001:0db8:0000:0000:0000:0000:0000:0001`). Useful for sorting and
4940
+ * byte-exact comparison.
4664
4941
  */
4665
4942
  canonicalForm() {
4666
4943
  return this.parsedAddress.map(paddedHex).join(':');
4667
4944
  }
4668
4945
  /**
4669
4946
  * Return the decimal form of the address
4670
- * @memberof Address6
4671
- * @instance
4672
4947
  * @returns {String}
4673
4948
  */
4674
4949
  decimal() {
@@ -4676,8 +4951,6 @@ function requireIpv6 () {
4676
4951
  }
4677
4952
  /**
4678
4953
  * Return the address as a BigInt
4679
- * @memberof Address6
4680
- * @instance
4681
4954
  * @returns {bigint}
4682
4955
  */
4683
4956
  bigInt() {
@@ -4685,8 +4958,6 @@ function requireIpv6 () {
4685
4958
  }
4686
4959
  /**
4687
4960
  * Return the last two groups of this address as an IPv4 address string
4688
- * @memberof Address6
4689
- * @instance
4690
4961
  * @returns {Address4}
4691
4962
  * @example
4692
4963
  * var address = new Address6('2001:4860:4001::1825:bf11');
@@ -4694,12 +4965,10 @@ function requireIpv6 () {
4694
4965
  */
4695
4966
  to4() {
4696
4967
  const binary = this.binaryZeroPad().split('');
4697
- return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16));
4968
+ return ipv4_1.Address4.fromHex(BigInt(`0b${binary.slice(96, 128).join('')}`).toString(16).padStart(8, '0'));
4698
4969
  }
4699
4970
  /**
4700
4971
  * Return the v4-in-v6 form of the address
4701
- * @memberof Address6
4702
- * @instance
4703
4972
  * @returns {String}
4704
4973
  */
4705
4974
  to4in6() {
@@ -4713,10 +4982,10 @@ function requireIpv6 () {
4713
4982
  return correct + infix + address4.address;
4714
4983
  }
4715
4984
  /**
4716
- * Return an object containing the Teredo properties of the address
4717
- * @memberof Address6
4718
- * @instance
4719
- * @returns {Object}
4985
+ * Decodes the Teredo tunneling fields embedded in this address. Returns the
4986
+ * Teredo prefix, server IPv4, client IPv4, raw flag bits, cone-NAT flag,
4987
+ * UDP port, and Microsoft-format flag breakdown (reserved, universal/local,
4988
+ * group/individual, nonce). Only meaningful for addresses in `2001::/32`.
4720
4989
  */
4721
4990
  inspectTeredo() {
4722
4991
  /*
@@ -4747,7 +5016,7 @@ function requireIpv6 () {
4747
5016
  const server4 = ipv4_1.Address4.fromHex(this.getBitsBase16(32, 64));
4748
5017
  const bitsForClient4 = this.getBits(96, 128);
4749
5018
  // eslint-disable-next-line no-bitwise
4750
- const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16));
5019
+ const client4 = ipv4_1.Address4.fromHex((bitsForClient4 ^ BigInt('0xffffffff')).toString(16).padStart(8, '0'));
4751
5020
  const flagsBase2 = this.getBitsBase2(64, 80);
4752
5021
  const coneNat = (0, common_1.testBit)(flagsBase2, 15);
4753
5022
  const reserved = (0, common_1.testBit)(flagsBase2, 14);
@@ -4770,10 +5039,9 @@ function requireIpv6 () {
4770
5039
  };
4771
5040
  }
4772
5041
  /**
4773
- * Return an object containing the 6to4 properties of the address
4774
- * @memberof Address6
4775
- * @instance
4776
- * @returns {Object}
5042
+ * Decodes the 6to4 tunneling fields embedded in this address. Returns the
5043
+ * 6to4 prefix and the embedded IPv4 gateway address. Only meaningful for
5044
+ * addresses in `2002::/16`.
4777
5045
  */
4778
5046
  inspect6to4() {
4779
5047
  /*
@@ -4789,8 +5057,6 @@ function requireIpv6 () {
4789
5057
  }
4790
5058
  /**
4791
5059
  * Return a v6 6to4 address from a v6 v4inv6 address
4792
- * @memberof Address6
4793
- * @instance
4794
5060
  * @returns {Address6}
4795
5061
  */
4796
5062
  to6to4() {
@@ -4807,9 +5073,80 @@ function requireIpv6 () {
4807
5073
  return new Address6(addr6to4);
4808
5074
  }
4809
5075
  /**
4810
- * Return a byte array
4811
- * @memberof Address6
4812
- * @instance
5076
+ * Embed an IPv4 address into a NAT64 IPv6 address using the encoding
5077
+ * defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
5078
+ * The default prefix is the well-known prefix `64:ff9b::/96`. The prefix
5079
+ * length must be one of 32, 40, 48, 56, 64, or 96; for prefixes shorter
5080
+ * than /64 the IPv4 octets are split around the reserved bits 64–71.
5081
+ * @example
5082
+ * Address6.fromAddress4Nat64('192.0.2.33').correctForm(); // '64:ff9b::c000:221'
5083
+ * Address6.fromAddress4Nat64('192.0.2.33', '2001:db8::/32').correctForm(); // '2001:db8:c000:221::'
5084
+ */
5085
+ static fromAddress4Nat64(address, prefix = '64:ff9b::/96') {
5086
+ const v4 = new ipv4_1.Address4(address);
5087
+ const prefix6 = new Address6(prefix);
5088
+ const pl = prefix6.subnetMask;
5089
+ if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
5090
+ throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
5091
+ }
5092
+ const prefixBits = prefix6.binaryZeroPad();
5093
+ const v4Bits = v4.binaryZeroPad();
5094
+ let bits;
5095
+ if (pl === 96) {
5096
+ bits = prefixBits.slice(0, 96) + v4Bits;
5097
+ }
5098
+ else {
5099
+ const beforeU = 64 - pl;
5100
+ bits =
5101
+ prefixBits.slice(0, pl) +
5102
+ v4Bits.slice(0, beforeU) +
5103
+ '00000000' +
5104
+ v4Bits.slice(beforeU) +
5105
+ '0'.repeat(128 - 72 - (32 - beforeU));
5106
+ }
5107
+ const hex = BigInt(`0b${bits}`).toString(16).padStart(32, '0');
5108
+ const groups = [];
5109
+ for (let i = 0; i < 8; i++) {
5110
+ groups.push(hex.slice(i * 4, (i + 1) * 4));
5111
+ }
5112
+ return new Address6(groups.join(':'));
5113
+ }
5114
+ /**
5115
+ * Extract the embedded IPv4 address from a NAT64 IPv6 address using the
5116
+ * encoding defined by [RFC 6052](https://datatracker.ietf.org/doc/html/rfc6052).
5117
+ * The default prefix is the well-known prefix `64:ff9b::/96`. Returns
5118
+ * `null` if this address is not contained within the given prefix.
5119
+ * @example
5120
+ * new Address6('64:ff9b::c000:221').toAddress4Nat64()!.correctForm(); // '192.0.2.33'
5121
+ */
5122
+ toAddress4Nat64(prefix = '64:ff9b::/96') {
5123
+ const prefix6 = new Address6(prefix);
5124
+ const pl = prefix6.subnetMask;
5125
+ if (pl !== 32 && pl !== 40 && pl !== 48 && pl !== 56 && pl !== 64 && pl !== 96) {
5126
+ throw new address_error_1.AddressError('NAT64 prefix length must be 32, 40, 48, 56, 64, or 96');
5127
+ }
5128
+ if (!this.isInSubnet(prefix6)) {
5129
+ return null;
5130
+ }
5131
+ const bits = this.binaryZeroPad();
5132
+ let v4Bits;
5133
+ if (pl === 96) {
5134
+ v4Bits = bits.slice(96, 128);
5135
+ }
5136
+ else {
5137
+ const beforeU = 64 - pl;
5138
+ v4Bits = bits.slice(pl, pl + beforeU) + bits.slice(72, 72 + (32 - beforeU));
5139
+ }
5140
+ const octets = [];
5141
+ for (let i = 0; i < 4; i++) {
5142
+ octets.push(parseInt(v4Bits.slice(i * 8, (i + 1) * 8), 2).toString());
5143
+ }
5144
+ return new ipv4_1.Address4(octets.join('.'));
5145
+ }
5146
+ /**
5147
+ * Return a byte array.
5148
+ *
5149
+ * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toByteArray())`.
4813
5150
  * @returns {Array}
4814
5151
  */
4815
5152
  toByteArray() {
@@ -4823,27 +5160,27 @@ function requireIpv6 () {
4823
5160
  return bytes;
4824
5161
  }
4825
5162
  /**
4826
- * Return an unsigned byte array
4827
- * @memberof Address6
4828
- * @instance
5163
+ * Return an unsigned byte array.
5164
+ *
5165
+ * To get a Node.js `Buffer`, wrap the result: `Buffer.from(address.toUnsignedByteArray())`.
4829
5166
  * @returns {Array}
4830
5167
  */
4831
5168
  toUnsignedByteArray() {
4832
5169
  return this.toByteArray().map(unsignByte);
4833
5170
  }
4834
5171
  /**
4835
- * Convert a byte array to an Address6 object
4836
- * @memberof Address6
4837
- * @static
5172
+ * Convert a byte array to an Address6 object.
5173
+ *
5174
+ * To convert from a Node.js `Buffer`, spread it: `Address6.fromByteArray([...buf])`.
4838
5175
  * @returns {Address6}
4839
5176
  */
4840
5177
  static fromByteArray(bytes) {
4841
5178
  return this.fromUnsignedByteArray(bytes.map(unsignByte));
4842
5179
  }
4843
5180
  /**
4844
- * Convert an unsigned byte array to an Address6 object
4845
- * @memberof Address6
4846
- * @static
5181
+ * Convert an unsigned byte array to an Address6 object.
5182
+ *
5183
+ * To convert from a Node.js `Buffer`, spread it: `Address6.fromUnsignedByteArray([...buf])`.
4847
5184
  * @returns {Address6}
4848
5185
  */
4849
5186
  static fromUnsignedByteArray(bytes) {
@@ -4858,8 +5195,6 @@ function requireIpv6 () {
4858
5195
  }
4859
5196
  /**
4860
5197
  * Returns true if the address is in the canonical form, false otherwise
4861
- * @memberof Address6
4862
- * @instance
4863
5198
  * @returns {boolean}
4864
5199
  */
4865
5200
  isCanonical() {
@@ -4867,8 +5202,6 @@ function requireIpv6 () {
4867
5202
  }
4868
5203
  /**
4869
5204
  * Returns true if the address is a link local address, false otherwise
4870
- * @memberof Address6
4871
- * @instance
4872
5205
  * @returns {boolean}
4873
5206
  */
4874
5207
  isLinkLocal() {
@@ -4881,53 +5214,81 @@ function requireIpv6 () {
4881
5214
  }
4882
5215
  /**
4883
5216
  * Returns true if the address is a multicast address, false otherwise
4884
- * @memberof Address6
4885
- * @instance
4886
5217
  * @returns {boolean}
4887
5218
  */
4888
5219
  isMulticast() {
4889
- return this.getType() === 'Multicast';
5220
+ const type = this.getType();
5221
+ return type === 'Multicast' || type.startsWith('Multicast ');
4890
5222
  }
4891
5223
  /**
4892
- * Returns true if the address is a v4-in-v6 address, false otherwise
4893
- * @memberof Address6
4894
- * @instance
5224
+ * Returns true if the address was written in v4-in-v6 dotted-quad notation
5225
+ * (e.g. `::ffff:127.0.0.1`), false otherwise. This is a notation-level flag
5226
+ * and does not reflect whether the address bits lie in the IPv4-mapped
5227
+ * (`::ffff:0:0/96`) subnet — for that, see {@link isMapped4}.
4895
5228
  * @returns {boolean}
4896
5229
  */
4897
5230
  is4() {
4898
5231
  return this.v4;
4899
5232
  }
5233
+ /**
5234
+ * Returns true if the address is an IPv4-mapped IPv6 address in
5235
+ * `::ffff:0:0/96` ([RFC 4291 §2.5.5.2](https://datatracker.ietf.org/doc/html/rfc4291#section-2.5.5.2)),
5236
+ * false otherwise. Unlike {@link is4}, this checks the underlying address
5237
+ * bits rather than the textual notation, so `::ffff:127.0.0.1` and
5238
+ * `::ffff:7f00:1` both return true.
5239
+ * @returns {boolean}
5240
+ */
5241
+ isMapped4() {
5242
+ return this.isInSubnet(IPV4_MAPPED_SUBNET);
5243
+ }
4900
5244
  /**
4901
5245
  * Returns true if the address is a Teredo address, false otherwise
4902
- * @memberof Address6
4903
- * @instance
4904
5246
  * @returns {boolean}
4905
5247
  */
4906
5248
  isTeredo() {
4907
- return this.isInSubnet(new Address6('2001::/32'));
5249
+ return this.isInSubnet(TEREDO_SUBNET);
4908
5250
  }
4909
5251
  /**
4910
5252
  * Returns true if the address is a 6to4 address, false otherwise
4911
- * @memberof Address6
4912
- * @instance
4913
5253
  * @returns {boolean}
4914
5254
  */
4915
5255
  is6to4() {
4916
- return this.isInSubnet(new Address6('2002::/16'));
5256
+ return this.isInSubnet(SIX_TO_FOUR_SUBNET);
4917
5257
  }
4918
5258
  /**
4919
5259
  * Returns true if the address is a loopback address, false otherwise
4920
- * @memberof Address6
4921
- * @instance
4922
5260
  * @returns {boolean}
4923
5261
  */
4924
5262
  isLoopback() {
4925
5263
  return this.getType() === 'Loopback';
4926
5264
  }
5265
+ /**
5266
+ * Returns true if the address is a Unique Local Address in `fc00::/7` ([RFC 4193](https://datatracker.ietf.org/doc/html/rfc4193)). ULAs are the IPv6 equivalent of IPv4 [RFC 1918](https://datatracker.ietf.org/doc/html/rfc1918) private addresses.
5267
+ * @returns {boolean}
5268
+ */
5269
+ isULA() {
5270
+ return this.isInSubnet(ULA_SUBNET);
5271
+ }
5272
+ /**
5273
+ * Returns true if the address is the unspecified address `::`.
5274
+ * @returns {boolean}
5275
+ */
5276
+ isUnspecified() {
5277
+ return this.getType() === 'Unspecified';
5278
+ }
5279
+ /**
5280
+ * Returns true if the address is in the documentation prefix `2001:db8::/32` ([RFC 3849](https://datatracker.ietf.org/doc/html/rfc3849)).
5281
+ * @returns {boolean}
5282
+ */
5283
+ isDocumentation() {
5284
+ return this.isInSubnet(DOCUMENTATION_SUBNET);
5285
+ }
4927
5286
  // #endregion
4928
5287
  // #region HTML
4929
5288
  /**
4930
- * @returns {String} the address in link form with a default port of 80
5289
+ * Returns the address as an HTTP URL with the host bracketed, e.g.
5290
+ * `http://[2001:db8::1]/`. If `optionalPort` is provided it is appended,
5291
+ * e.g. `http://[2001:db8::1]:8080/`.
4931
5292
  */
4932
5293
  href(optionalPort) {
4933
5294
  if (optionalPort === undefined) {
@@ -4939,7 +5300,12 @@ function requireIpv6 () {
4939
5300
  return `http://[${this.correctForm()}]${optionalPort}/`;
4940
5301
  }
4941
5302
  /**
4942
- * @returns {String} a link suitable for conveying the address via a URL hash
5303
+ * Returns an HTML `<a>` element whose `href` encodes the address in a URL
5304
+ * hash fragment (default prefix `/#address=`). Useful for linking between
5305
+ * pages of an address-inspector UI.
5306
+ * @param options.className - CSS class for the rendered `<a>` element
5307
+ * @param options.prefix - hash prefix prepended to the address (default `/#address=`)
5308
+ * @param options.v4 - when true, render the address in v4-in-v6 form
4943
5309
  */
4944
5310
  link(options) {
4945
5311
  if (!options) {
@@ -4959,10 +5325,13 @@ function requireIpv6 () {
4959
5325
  formFunction = this.to4in6;
4960
5326
  }
4961
5327
  const form = formFunction.call(this);
5328
+ const safeHref = helpers.escapeHtml(`${options.prefix}${form}`);
5329
+ const safeForm = helpers.escapeHtml(form);
4962
5330
  if (options.className) {
4963
- return `<a href="${options.prefix}${form}" class="${options.className}">${form}</a>`;
5331
+ const safeClass = helpers.escapeHtml(options.className);
5332
+ return `<a href="${safeHref}" class="${safeClass}">${safeForm}</a>`;
4964
5333
  }
4965
- return `<a href="${options.prefix}${form}">${form}</a>`;
5334
+ return `<a href="${safeHref}">${safeForm}</a>`;
4966
5335
  }
4967
5336
  /**
4968
5337
  * Groups an address
@@ -4971,13 +5340,13 @@ function requireIpv6 () {
4971
5340
  group() {
4972
5341
  if (this.elidedGroups === 0) {
4973
5342
  // The simple case
4974
- return helpers.simpleGroup(this.address).join(':');
5343
+ return helpers.simpleGroup(this.addressMinusSuffix).join(':');
4975
5344
  }
4976
5345
  assert(typeof this.elidedGroups === 'number');
4977
5346
  assert(typeof this.elisionBegin === 'number');
4978
5347
  // The elided case
4979
5348
  const output = [];
4980
- const [left, right] = this.address.split('::');
5349
+ const [left, right] = this.addressMinusSuffix.split('::');
4981
5350
  if (left.length) {
4982
5351
  output.push(...helpers.simpleGroup(left));
4983
5352
  }
@@ -5007,8 +5376,6 @@ function requireIpv6 () {
5007
5376
  /**
5008
5377
  * Generate a regular expression string that can be used to find or validate
5009
5378
  * all variations of this address
5010
- * @memberof Address6
5011
- * @instance
5012
5379
  * @param {boolean} substringSearch
5013
5380
  * @returns {string}
5014
5381
  */
@@ -5053,8 +5420,6 @@ function requireIpv6 () {
5053
5420
  /**
5054
5421
  * Generate a regular expression that can be used to find or validate all
5055
5422
  * variations of this address.
5056
- * @memberof Address6
5057
- * @instance
5058
5423
  * @param {boolean} substringSearch
5059
5424
  * @returns {RegExp}
5060
5425
  */
@@ -5063,6 +5428,15 @@ function requireIpv6 () {
5063
5428
  }
5064
5429
  }
5065
5430
  ipv6.Address6 = Address6;
5431
+ const TYPE_SUBNETS = Object.keys(constants6.TYPES).map((subnet) => [
5432
+ new Address6(subnet),
5433
+ constants6.TYPES[subnet],
5434
+ ]);
5435
+ const TEREDO_SUBNET = new Address6('2001::/32');
5436
+ const SIX_TO_FOUR_SUBNET = new Address6('2002::/16');
5437
+ const ULA_SUBNET = new Address6('fc00::/7');
5438
+ const DOCUMENTATION_SUBNET = new Address6('2001:db8::/32');
5439
+ const IPV4_MAPPED_SUBNET = new Address6('::ffff:0:0/96');
5066
5440
 
5067
5441
  return ipv6;
5068
5442
  }
@@ -5072,7 +5446,7 @@ var hasRequiredIpAddress;
5072
5446
  function requireIpAddress () {
5073
5447
  if (hasRequiredIpAddress) return ipAddress;
5074
5448
  hasRequiredIpAddress = 1;
5075
- (function (exports$1) {
5449
+ (function (exports) {
5076
5450
  var __createBinding = (ipAddress && ipAddress.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5077
5451
  if (k2 === undefined) k2 = k;
5078
5452
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -5096,16 +5470,16 @@ function requireIpAddress () {
5096
5470
  __setModuleDefault(result, mod);
5097
5471
  return result;
5098
5472
  };
5099
- Object.defineProperty(exports$1, "__esModule", { value: true });
5100
- exports$1.v6 = exports$1.AddressError = exports$1.Address6 = exports$1.Address4 = void 0;
5101
- var ipv4_1 = requireIpv4();
5102
- Object.defineProperty(exports$1, "Address4", { enumerable: true, get: function () { return ipv4_1.Address4; } });
5103
- var ipv6_1 = requireIpv6();
5104
- Object.defineProperty(exports$1, "Address6", { enumerable: true, get: function () { return ipv6_1.Address6; } });
5105
- var address_error_1 = requireAddressError();
5106
- Object.defineProperty(exports$1, "AddressError", { enumerable: true, get: function () { return address_error_1.AddressError; } });
5107
- const helpers = __importStar(requireHelpers$1());
5108
- exports$1.v6 = { helpers };
5473
+ Object.defineProperty(exports, "__esModule", { value: true });
5474
+ exports.v6 = exports.AddressError = exports.Address6 = exports.Address4 = void 0;
5475
+ var ipv4_1 = /*@__PURE__*/ requireIpv4();
5476
+ Object.defineProperty(exports, "Address4", { enumerable: true, get: function () { return ipv4_1.Address4; } });
5477
+ var ipv6_1 = /*@__PURE__*/ requireIpv6();
5478
+ Object.defineProperty(exports, "Address6", { enumerable: true, get: function () { return ipv6_1.Address6; } });
5479
+ var address_error_1 = /*@__PURE__*/ requireAddressError();
5480
+ Object.defineProperty(exports, "AddressError", { enumerable: true, get: function () { return address_error_1.AddressError; } });
5481
+ const helpers = __importStar(/*@__PURE__*/ requireHelpers$1());
5482
+ exports.v6 = { helpers };
5109
5483
 
5110
5484
  } (ipAddress));
5111
5485
  return ipAddress;
@@ -5121,7 +5495,7 @@ function requireHelpers () {
5121
5495
  const util_1 = requireUtil();
5122
5496
  const constants_1 = requireConstants$2();
5123
5497
  const stream = require$$2$1;
5124
- const ip_address_1 = requireIpAddress();
5498
+ const ip_address_1 = /*@__PURE__*/ requireIpAddress();
5125
5499
  const net$1 = net;
5126
5500
  /**
5127
5501
  * Validates the provided SocksClientOptions
@@ -5342,7 +5716,7 @@ var hasRequiredSocksclient;
5342
5716
  function requireSocksclient () {
5343
5717
  if (hasRequiredSocksclient) return socksclient;
5344
5718
  hasRequiredSocksclient = 1;
5345
- (function (exports$1) {
5719
+ (function (exports) {
5346
5720
  var __awaiter = (socksclient && socksclient.__awaiter) || function (thisArg, _arguments, P, generator) {
5347
5721
  function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5348
5722
  return new (P || (P = Promise))(function (resolve, reject) {
@@ -5352,8 +5726,8 @@ function requireSocksclient () {
5352
5726
  step((generator = generator.apply(thisArg, _arguments || [])).next());
5353
5727
  });
5354
5728
  };
5355
- Object.defineProperty(exports$1, "__esModule", { value: true });
5356
- exports$1.SocksClientError = exports$1.SocksClient = void 0;
5729
+ Object.defineProperty(exports, "__esModule", { value: true });
5730
+ exports.SocksClientError = exports.SocksClient = void 0;
5357
5731
  const events_1 = require$$0;
5358
5732
  const net$1 = net;
5359
5733
  const smart_buffer_1 = requireSmartbuffer();
@@ -5361,8 +5735,8 @@ function requireSocksclient () {
5361
5735
  const helpers_1 = requireHelpers();
5362
5736
  const receivebuffer_1 = requireReceivebuffer();
5363
5737
  const util_1 = requireUtil();
5364
- Object.defineProperty(exports$1, "SocksClientError", { enumerable: true, get: function () { return util_1.SocksClientError; } });
5365
- const ip_address_1 = requireIpAddress();
5738
+ Object.defineProperty(exports, "SocksClientError", { enumerable: true, get: function () { return util_1.SocksClientError; } });
5739
+ const ip_address_1 = /*@__PURE__*/ requireIpAddress();
5366
5740
  class SocksClient extends events_1.EventEmitter {
5367
5741
  constructor(options) {
5368
5742
  super();
@@ -6133,7 +6507,7 @@ function requireSocksclient () {
6133
6507
  return Object.assign({}, this.options);
6134
6508
  }
6135
6509
  }
6136
- exports$1.SocksClient = SocksClient;
6510
+ exports.SocksClient = SocksClient;
6137
6511
 
6138
6512
  } (socksclient));
6139
6513
  return socksclient;
@@ -6144,7 +6518,7 @@ var hasRequiredBuild;
6144
6518
  function requireBuild () {
6145
6519
  if (hasRequiredBuild) return build$1;
6146
6520
  hasRequiredBuild = 1;
6147
- (function (exports$1) {
6521
+ (function (exports) {
6148
6522
  var __createBinding = (build$1 && build$1.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6149
6523
  if (k2 === undefined) k2 = k;
6150
6524
  var desc = Object.getOwnPropertyDescriptor(m, k);
@@ -6156,11 +6530,11 @@ function requireBuild () {
6156
6530
  if (k2 === undefined) k2 = k;
6157
6531
  o[k2] = m[k];
6158
6532
  }));
6159
- var __exportStar = (build$1 && build$1.__exportStar) || function(m, exports$1) {
6160
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports$1, p)) __createBinding(exports$1, m, p);
6533
+ var __exportStar = (build$1 && build$1.__exportStar) || function(m, exports) {
6534
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
6161
6535
  };
6162
- Object.defineProperty(exports$1, "__esModule", { value: true });
6163
- __exportStar(requireSocksclient(), exports$1);
6536
+ Object.defineProperty(exports, "__esModule", { value: true });
6537
+ __exportStar(requireSocksclient(), exports);
6164
6538
 
6165
6539
  } (build$1));
6166
6540
  return build$1;
@@ -6504,6 +6878,85 @@ const getCurrentUser = () => {
6504
6878
  }
6505
6879
  };
6506
6880
 
6881
+ /**
6882
+ * Cookie 工具:把 Set-Cookie 头(或被 `'; '` 拼接污染过的脏 cookie 串)
6883
+ * 归一化为合法的 `Cookie` 请求头值。
6884
+ *
6885
+ * 与浏览器一致的最小行为:
6886
+ * - 丢弃 cookie 属性段(Path / Domain / Max-Age / Expires / Secure / HttpOnly / SameSite / Priority / Partitioned)
6887
+ * - 过滤 `Max-Age <= 0` 或 `Expires` 已过期的 cookie(浏览器不会写入 jar,也就不会发送)
6888
+ * - 保持原有出现顺序,不按 name 去重(浏览器在不同 domain/path 下同名 cookie 会一并发送)
6889
+ */
6890
+ const COOKIE_ATTRIBUTE_KEYS = new Set([
6891
+ 'path',
6892
+ 'domain',
6893
+ 'max-age',
6894
+ 'expires',
6895
+ 'secure',
6896
+ 'httponly',
6897
+ 'samesite',
6898
+ 'priority',
6899
+ 'partitioned',
6900
+ ]);
6901
+ function splitSegments(raw) {
6902
+ return raw
6903
+ .split(';')
6904
+ .map(s => s.trim())
6905
+ .filter(Boolean);
6906
+ }
6907
+ function isAttributeKey(key) {
6908
+ return COOKIE_ATTRIBUTE_KEYS.has(key.toLowerCase());
6909
+ }
6910
+ /**
6911
+ * 清洗任意来源的 Cookie 字符串:
6912
+ * - 兼容标准 `name=value; name=value` 格式(幂等)
6913
+ * - 兼容把多条 Set-Cookie 用 `'; '` 拼接得到的脏串
6914
+ */
6915
+ function sanitizeCookieHeader(cookieHeader) {
6916
+ if (!cookieHeader)
6917
+ return '';
6918
+ const segments = splitSegments(cookieHeader);
6919
+ const entries = [];
6920
+ let current = null;
6921
+ for (const seg of segments) {
6922
+ const eqIdx = seg.indexOf('=');
6923
+ const key = (eqIdx < 0 ? seg : seg.slice(0, eqIdx)).trim();
6924
+ const val = eqIdx < 0 ? '' : seg.slice(eqIdx + 1).trim();
6925
+ if (!key)
6926
+ continue;
6927
+ if (isAttributeKey(key)) {
6928
+ if (!current)
6929
+ continue;
6930
+ const lk = key.toLowerCase();
6931
+ if (lk === 'max-age') {
6932
+ const n = Number(val);
6933
+ if (Number.isFinite(n) && n <= 0)
6934
+ current.expired = true;
6935
+ }
6936
+ else if (lk === 'expires') {
6937
+ const t = Date.parse(val);
6938
+ if (!Number.isNaN(t) && t <= Date.now())
6939
+ current.expired = true;
6940
+ }
6941
+ continue;
6942
+ }
6943
+ current = { name: key, value: val, expired: false };
6944
+ entries.push(current);
6945
+ }
6946
+ return entries
6947
+ .filter(e => !e.expired)
6948
+ .map(e => `${e.name}=${e.value}`)
6949
+ .join('; ');
6950
+ }
6951
+ /**
6952
+ * 从 `response.headers['set-cookie']` 数组构建可用于 `Cookie` 请求头的字符串。
6953
+ */
6954
+ function buildCookieHeaderFromSetCookies(setCookies) {
6955
+ if (!setCookies || setCookies.length === 0)
6956
+ return '';
6957
+ return sanitizeCookieHeader(setCookies.join('; '));
6958
+ }
6959
+
6507
6960
  function isVerboseEnabled() {
6508
6961
  return process.argv.includes('--verbose');
6509
6962
  }
@@ -6654,7 +7107,7 @@ function printApiResponseLog(title, result) {
6654
7107
  }
6655
7108
  async function request({ url, method, data, headers, params, }) {
6656
7109
  const config = getTTMGRC();
6657
- const cookie = config?.cookie;
7110
+ const cookie = sanitizeCookieHeader(config?.cookie);
6658
7111
  const proxyConfig = getAxiosProxyConfig();
6659
7112
  if (isVerboseEnabled()) {
6660
7113
  printApiRequestLog({
@@ -11541,10 +11994,13 @@ async function login(options) {
11541
11994
  process.exit(1);
11542
11995
  }
11543
11996
  else {
11997
+ const setCookies = response?.headers['set-cookie'];
11998
+ const cookie = buildCookieHeaderFromSetCookies(setCookies);
11999
+ log('Parsed cookies', { rawCount: setCookies?.length ?? 0, kept: cookie ? cookie.split('; ').length : 0 });
11544
12000
  const loginData = {
11545
12001
  email,
11546
12002
  user_id: response?.data?.data?.user_id,
11547
- cookie: response?.headers['set-cookie'].join('; '),
12003
+ cookie,
11548
12004
  };
11549
12005
  log('Login success', { user_id: loginData.user_id, email: loginData.email });
11550
12006
  setTTMGRC(loginData);
@@ -11818,7 +12274,7 @@ async function upload({ clientKey, note = '--', dir, }) {
11818
12274
  }
11819
12275
  }
11820
12276
 
11821
- var version = "0.3.8-beta.2";
12277
+ var version = "0.3.8-beta.3";
11822
12278
  var pkg = {
11823
12279
  version: version};
11824
12280