Skip to content

Commit dcf33df

Browse files
Add browser support (#36)
Co-authored-by: Sindre Sorhus <[email protected]>
1 parent f2a688e commit dcf33df

File tree

3 files changed

+80
-4
lines changed

3 files changed

+80
-4
lines changed

browser.js

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/* eslint-env browser */
2+
'use strict';
3+
import pEvent from 'p-event';
4+
import isIp from 'is-ip';
5+
6+
const getIp = async ({isSecondTry = false} = {}) => {
7+
try {
8+
const peerConnection = new RTCPeerConnection({iceServers: []});
9+
10+
peerConnection.createDataChannel('');
11+
peerConnection.createOffer(peerConnection.setLocalDescription.bind(peerConnection), () => {});
12+
13+
const {candidate} = await pEvent(peerConnection, 'icecandidate', {
14+
timeout: 10000
15+
});
16+
17+
peerConnection.close();
18+
19+
if (candidate && candidate.candidate) {
20+
const result = candidate.candidate.split(' ')[4];
21+
if (result.endsWith('.local')) {
22+
if (isSecondTry) {
23+
return;
24+
}
25+
26+
const inputDevices = await navigator.mediaDevices.enumerateDevices();
27+
const inputDeviceTypes = new Set(inputDevices.map(({kind}) => kind));
28+
29+
const constraints = {};
30+
31+
if (inputDeviceTypes.has('audioinput')) {
32+
constraints.audio = true;
33+
} else if (inputDeviceTypes.has('videoinput')) {
34+
constraints.video = true;
35+
} else {
36+
return;
37+
}
38+
39+
const mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
40+
for (const track of mediaStream.getTracks()) {
41+
track.stop();
42+
}
43+
44+
return await getIp({isSecondTry: true});
45+
}
46+
47+
return result;
48+
}
49+
} catch {}
50+
};
51+
52+
export const v4 = async () => {
53+
const result = await getIp();
54+
if (isIp.v4(result)) {
55+
return result;
56+
}
57+
};
58+
59+
v4.sync = () => undefined;
60+
61+
export const v6 = async () => {
62+
const result = await getIp();
63+
if (isIp.v6(result)) {
64+
return result;
65+
}
66+
};
67+
68+
v6.sync = () => undefined;

package.json

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,13 @@
1818
},
1919
"files": [
2020
"index.js",
21-
"index.d.ts"
21+
"index.d.ts",
22+
"browser.js"
2223
],
24+
"exports": {
25+
"browser": "./browser.js",
26+
"default": "./index.js"
27+
},
2328
"keywords": [
2429
"ip",
2530
"ipv6",
@@ -34,11 +39,14 @@
3439
],
3540
"dependencies": {
3641
"default-gateway": "^6.0.0",
37-
"ipaddr.js": "^1.9.1"
42+
"ipaddr.js": "^1.9.1",
43+
"is-ip": "^3.1.0",
44+
"p-event": "^4.2.0"
3845
},
3946
"devDependencies": {
4047
"ava": "^2.4.0",
4148
"tsd": "^0.13.1",
4249
"xo": "^0.32.1"
43-
}
50+
},
51+
"browser": "browser.js"
4452
}

readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ console.log(internalIp.v4.sync())
3030

3131
The module returns the address of the internet-facing interface, as determined from the default gateway. When the address cannot be determined for any reason, `undefined` will be returned.
3232

33-
The module relies on operating systems tools. On Linux and Android, the `ip` command must be available, which depending on distribution might not be installed by default. It is usually provided by the `iproute2` package.
33+
The module relies on operating systems tools. On Linux and Android, the `ip` command must be available, which depending on distribution might not be installed by default. It is usually provided by the `iproute2` package. `.v4.sync()` and `.v6.sync()` are not supported in browsers and just return `undefined`.
3434

3535
## Related
3636

0 commit comments

Comments
 (0)