Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use named exports and allow getting either IPv4 or IPv6 #63

Merged
merged 5 commits into from
Jun 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions browser.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import isIp from 'is-ip';
import {createPublicIp, IpNotFoundError} from './core.js';

export class CancelError extends Error {
constructor() {
Expand All @@ -11,12 +12,7 @@ export class CancelError extends Error {
}
}

export class IpNotFoundError extends Error {
constructor(options) {
super('Could not get the public IP address', options);
this.name = 'IpNotFoundError';
}
}
export {IpNotFoundError} from './core.js';

const defaults = {
timeout: 5000,
Expand Down Expand Up @@ -100,10 +96,12 @@ const queryHttps = (version, options) => {
return promise;
};

const publicIp = {};

publicIp.v4 = options => queryHttps('v4', {...defaults, ...options});
export default createPublicIp(publicIpv4, publicIpv6);

publicIp.v6 = options => queryHttps('v6', {...defaults, ...options});
export function publicIpv4(options) {
return queryHttps('v4', {...defaults, ...options});
}

export default publicIp;
export function publicIpv6(options) {
return queryHttps('v6', {...defaults, ...options});
}
40 changes: 40 additions & 0 deletions core.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import AggregateError from 'aggregate-error'; // Use built-in when targeting Node.js 16

export class IpNotFoundError extends Error {
constructor(options) {
super('Could not get the public IP address', options);
this.name = 'IpNotFoundError';
}
}

export function createPublicIp(publicIpv4, publicIpv6) {
return function publicIp(options) { // eslint-disable-line func-names
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is named to improve error messages but xo doesn't allow it to be immediately exported.

image

const ipv4Promise = publicIpv4(options);
const ipv6Promise = publicIpv6(options);

const promise = (async () => {
try {
const ipv6 = await ipv6Promise;
ipv4Promise.cancel();
return ipv6;
} catch (ipv6Error) {
if (!(ipv6Error instanceof IpNotFoundError)) {
throw ipv6Error;
}

try {
return await ipv4Promise;
} catch (ipv4Error) {
throw new AggregateError([ipv4Error, ipv6Error]);
}
}
})();

promise.cancel = () => {
ipv4Promise.cancel();
ipv6Promise.cancel();
};

return promise;
};
}
76 changes: 45 additions & 31 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ export interface Options {

@example
```
import publicIp from 'public-ip';
import {publicIpv6} from 'public-ip';

await publicIp.v6({
await publicIpv6({
fallbackUrls: [
'https://ifconfig.co/ip'
]
Expand All @@ -45,44 +45,58 @@ export type CancelablePromise<T> = Promise<T> & {
cancel(): void;
};

declare const publicIp: {
/**
Get your public IP address - very fast!
/**
Get your public IP address - very fast!

In Node.js, it queries the DNS records of OpenDNS, Google DNS, and HTTPS services to determine your IP address. In browsers, it uses the excellent [icanhaz](https://github.com/major/icanhaz) and [ipify](https://ipify.org) services through HTTPS.
In Node.js, it queries the DNS records of OpenDNS, Google DNS, and HTTPS services to determine your IP address. In browsers, it uses the excellent [icanhaz](https://github.com/major/icanhaz) and [ipify](https://ipify.org) services through HTTPS.

@returns Your public IPv4 address. A `.cancel()` method is available on the promise, which can be used to cancel the request.
@throws On error or timeout.
@returns Your public IPv6 address or as a fallback, your public IPv4 address. A `.cancel()` method is available on the promise, which can be used to cancel the request.
@throws On error or timeout.

@example
```
import publicIp from 'public-ip';
@example
```
import publicIp from 'public-ip';

console.log(await publicIp.v4());
//=> '46.5.21.123'
```
*/
v4(options?: Options): CancelablePromise<string>;
console.log(await publicIp()); // Falls back to IPv4
//=> 'fe80::200:f8ff:fe21:67cf'
```
*/
export function publicIp(options?: Options): CancelablePromise<string>;

/**
Get your public IP address - very fast!
/**
Get your public IP address - very fast!

In Node.js, it queries the DNS records of OpenDNS, Google DNS, and HTTPS services to determine your IP address. In browsers, it uses the excellent [icanhaz](https://github.com/major/icanhaz) and [ipify](https://ipify.org) services through HTTPS.
In Node.js, it queries the DNS records of OpenDNS, Google DNS, and HTTPS services to determine your IP address. In browsers, it uses the excellent [icanhaz](https://github.com/major/icanhaz) and [ipify](https://ipify.org) services through HTTPS.

@returns Your public IPv6 address. A `.cancel()` method is available on the promise, which can be used to cancel the request.
@throws On error or timeout.
@returns Your public IPv4 address. A `.cancel()` method is available on the promise, which can be used to cancel the request.
@throws On error or timeout.

@example
```
import publicIp from 'public-ip';
@example
```
import {publicIpv4} from 'public-ip';

console.log(await publicIp.v6());
//=> 'fe80::200:f8ff:fe21:67cf'
```
*/
v6(options?: Options): CancelablePromise<string>;
};
console.log(await publicIpv4());
//=> '46.5.21.123'
```
*/
export function publicIpv4(options?: Options): CancelablePromise<string>;

/**
Get your public IP address - very fast!

In Node.js, it queries the DNS records of OpenDNS, Google DNS, and HTTPS services to determine your IP address. In browsers, it uses the excellent [icanhaz](https://github.com/major/icanhaz) and [ipify](https://ipify.org) services through HTTPS.

@returns Your public IPv6 address. A `.cancel()` method is available on the promise, which can be used to cancel the request.
@throws On error or timeout.

export default publicIp;
@example
```
import {publicIpv6} from 'public-ip';

console.log(await publicIpv6());
//=> 'fe80::200:f8ff:fe21:67cf'
```
*/
export function publicIpv6(options?: Options): CancelablePromise<string>;

export {CancelError} from 'got';
20 changes: 7 additions & 13 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,9 @@ import dgram from 'node:dgram';
import dns from 'dns-socket';
import got, {CancelError} from 'got';
import isIp from 'is-ip';
import {createPublicIp, IpNotFoundError} from './core.js';

export class IpNotFoundError extends Error {
constructor(options) {
super('Could not get the public IP address', options);
this.name = 'IpNotFoundError';
}
}
export {IpNotFoundError} from './core.js';

const defaults = {
timeout: 5000,
Expand Down Expand Up @@ -228,9 +224,9 @@ const queryAll = (version, options) => {
return promise;
};

const publicIp = {};
export default createPublicIp(publicIpv4, publicIpv6);

publicIp.v4 = options => {
export function publicIpv4(options) {
options = {
...defaults,
...options,
Expand All @@ -245,9 +241,9 @@ publicIp.v4 = options => {
}

return queryDns('v4', options);
};
}

publicIp.v6 = options => {
export function publicIpv6(options) {
options = {
...defaults,
...options,
Expand All @@ -262,8 +258,6 @@ publicIp.v6 = options => {
}

return queryDns('v6', options);
};

export default publicIp;
}

export {CancelError} from 'got';
28 changes: 17 additions & 11 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import {expectType} from 'tsd';
import publicIp, {CancelablePromise} from './index.js';
import {publicIp, publicIpv4, publicIpv6, CancelablePromise} from './index.js';

expectType<CancelablePromise<string>>(publicIp.v4());
expectType<CancelablePromise<string>>(publicIp.v4({onlyHttps: true}));
expectType<CancelablePromise<string>>(publicIp.v4({timeout: 10}));
expectType<CancelablePromise<string>>(publicIp.v4({fallbackUrls: ['https://ifconfig.io']}));
publicIp.v4().cancel();
expectType<CancelablePromise<string>>(publicIpv4());
expectType<CancelablePromise<string>>(publicIpv4({onlyHttps: true}));
expectType<CancelablePromise<string>>(publicIpv4({timeout: 10}));
expectType<CancelablePromise<string>>(publicIpv4({fallbackUrls: ['https://ifconfig.io']}));
publicIpv4().cancel();

expectType<CancelablePromise<string>>(publicIp.v6());
expectType<CancelablePromise<string>>(publicIp.v6({onlyHttps: true}));
expectType<CancelablePromise<string>>(publicIp.v6({timeout: 10}));
expectType<CancelablePromise<string>>(publicIp.v6({fallbackUrls: ['https://ifconfig.io']}));
publicIp.v6().cancel();
expectType<CancelablePromise<string>>(publicIpv6());
expectType<CancelablePromise<string>>(publicIpv6({onlyHttps: true}));
expectType<CancelablePromise<string>>(publicIpv6({timeout: 10}));
expectType<CancelablePromise<string>>(publicIpv6({fallbackUrls: ['https://ifconfig.io']}));
publicIpv6().cancel();

expectType<CancelablePromise<string>>(publicIp());
expectType<CancelablePromise<string>>(publicIp({onlyHttps: true}));
expectType<CancelablePromise<string>>(publicIp({timeout: 10}));
expectType<CancelablePromise<string>>(publicIp({fallbackUrls: ['https://ifconfig.io']}));
publicIp().cancel();
4 changes: 2 additions & 2 deletions mocks/stub.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,12 @@ export default function stub(objectPath, propertyName, ignoreIndex) {
sinon.stub(objectPath, propertyName).callsFake(stub);

return {
ignore: _ignoreRegExp => {
ignore(_ignoreRegExp) {
ignoreRegExp = _ignoreRegExp;
},
ignored: () => ignored.length,
called: () => objectPath[propertyName].callCount,
restore: () => {
restore() {
ignoreRegExp = undefined;
ignored = [];
objectPath[propertyName].resetHistory();
Expand Down
11 changes: 7 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@
"index.js",
"index.d.ts",
"browser.js",
"browser.d.ts"
"browser.d.ts",
"core.js"
],
"keywords": [
"get",
Expand All @@ -41,15 +42,17 @@
"dns"
],
"dependencies": {
"aggregate-error": "^4.0.1",
"dns-socket": "^4.2.2",
"got": "^12.0.0",
"is-ip": "^3.1.0"
},
"devDependencies": {
"ava": "^3.15.0",
"ava": "^4.2.0",
"sinon": "^12.0.1",
"tsd": "^0.19.0",
"xo": "^0.47.0"
"time-span": "^5.0.0",
"tsd": "^0.20.0",
"xo": "^0.49.0"
},
"xo": {
"envs": [
Expand Down
18 changes: 11 additions & 7 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,23 @@ npm install public-ip
## Usage

```js
import publicIp from 'public-ip';
import publicIp, {publicIpv4, publicIpv6} from 'public-ip';

console.log(await publicIp.v4());
console.log(await publicIpv4());
//=> '46.5.21.123'

console.log(await publicIp.v6());
console.log(await publicIpv6());
//=> 'fe80::200:f8ff:fe21:67cf'

console.log(await publicIp()); // Falls back to IPv4
//=> 'fe80::200:f8ff:fe21:67cf'
```

## API

### publicIp.v4(options?)
### publicIp.v6(options?)
### publicIp(options?)
### publicIpv4(options?)
### publicIpv6(options?)

Returns a `Promise<string>` with your public IPv4 or IPv6 address. Rejects on error or timeout. A `.cancel()` method is available on the promise, which can be used to cancel the request.

Expand All @@ -48,9 +52,9 @@ Default: `[]`
Add your own custom HTTPS endpoints to get the public IP from. They will only be used if everything else fails. Any service used as fallback *must* return the IP as a plain string.

```js
import publicIp from 'public-ip';
import {publicIpv6} from 'public-ip';

await publicIp.v6({
await publicIpv6({
fallbackUrls: [
'https://ifconfig.co/ip'
]
Expand Down
7 changes: 4 additions & 3 deletions test-browser.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
// Comment out the `is-ip` dependency, launch a local server, and then load the HTMl file.
import publicIp from './browser.js';
import publicIp, {publicIpv4} from './browser.js';

console.log('IP:', await publicIp.v4());
console.log('IP:', await publicIp.v4({
console.log('IP:', await publicIpv4());
console.log('IP:', await publicIpv4({
fallbackUrls: [
'https://ifconfig.me',
],
}));
console.log('IP:', await publicIp());
Loading