diff --git a/code/lib/core-server/package.json b/code/lib/core-server/package.json index 8c00601edba7..467633f875d9 100644 --- a/code/lib/core-server/package.json +++ b/code/lib/core-server/package.json @@ -87,7 +87,6 @@ "express": "^4.19.2", "fs-extra": "^11.1.0", "globby": "^14.0.1", - "ip": "^2.0.1", "lodash": "^4.17.21", "open": "^8.4.0", "pretty-hrtime": "^1.0.3", @@ -105,7 +104,6 @@ "devDependencies": { "@storybook/addon-docs": "workspace:*", "@types/compression": "^1.7.0", - "@types/ip": "^1.1.0", "@types/node-fetch": "^2.5.7", "@types/ws": "^8", "boxen": "^7.1.1", diff --git a/code/lib/core-server/src/utils/__tests__/server-address.test.ts b/code/lib/core-server/src/utils/__tests__/server-address.test.ts index 3c2fb3defe91..4b3636ee9e84 100644 --- a/code/lib/core-server/src/utils/__tests__/server-address.test.ts +++ b/code/lib/core-server/src/utils/__tests__/server-address.test.ts @@ -1,13 +1,24 @@ import { describe, beforeEach, it, expect, vi } from 'vitest'; -import ip from 'ip'; +import os, { type NetworkInterfaceInfoIPv4 } from 'os'; import { getServerAddresses } from '../server-address'; -vi.mock('ip'); -const mockedIp = vi.mocked(ip); +vi.mock('os'); +const mockedOs = vi.mocked(os); describe('getServerAddresses', () => { + const mockedNetworkAddress: NetworkInterfaceInfoIPv4 = { + address: '192.168.0.5', + netmask: '255.255.255.0', + family: 'IPv4', + mac: '01:02:03:0a:0b:0c', + internal: false, + cidr: '192.168.0.5/24', + }; + beforeEach(() => { - mockedIp.address.mockReturnValue('192.168.0.5'); + mockedOs.networkInterfaces.mockReturnValue({ + eth0: [mockedNetworkAddress], + }); }); it('builds addresses with a specified host', () => { @@ -19,6 +30,15 @@ describe('getServerAddresses', () => { it('builds addresses with local IP when host is not specified', () => { const { address, networkAddress } = getServerAddresses(9009, '', 'http'); expect(address).toEqual('http://localhost:9009/'); - expect(networkAddress).toEqual('http://192.168.0.5:9009/'); + expect(networkAddress).toEqual(`http://${mockedNetworkAddress.address}:9009/`); + }); + + it('builds addresses with default address when host is not specified and external IPv4 is not found', () => { + mockedOs.networkInterfaces.mockReturnValueOnce({ + eth0: [{ ...mockedNetworkAddress, internal: true }], + }); + const { address, networkAddress } = getServerAddresses(9009, '', 'http'); + expect(address).toEqual('http://localhost:9009/'); + expect(networkAddress).toEqual('http://0.0.0.0:9009/'); }); }); diff --git a/code/lib/core-server/src/utils/server-address.test.ts b/code/lib/core-server/src/utils/server-address.test.ts index e1a0b757c2ee..85299cb12f7b 100644 --- a/code/lib/core-server/src/utils/server-address.test.ts +++ b/code/lib/core-server/src/utils/server-address.test.ts @@ -2,7 +2,7 @@ import { describe, it, expect, vi } from 'vitest'; import detectPort from 'detect-port'; import { getServerAddresses, getServerPort, getServerChannelUrl } from './server-address'; -vi.mock('ip'); +vi.mock('os'); vi.mock('detect-port'); vi.mock('@storybook/node-logger'); diff --git a/code/lib/core-server/src/utils/server-address.ts b/code/lib/core-server/src/utils/server-address.ts index bfcb2ba969d9..4d49cf8a980a 100644 --- a/code/lib/core-server/src/utils/server-address.ts +++ b/code/lib/core-server/src/utils/server-address.ts @@ -1,4 +1,4 @@ -import ip from 'ip'; +import os from 'os'; import { logger } from '@storybook/node-logger'; import detectFreePort from 'detect-port'; @@ -10,7 +10,7 @@ export function getServerAddresses( initialPath?: string ) { const address = new URL(`${proto}://localhost:${port}/`); - const networkAddress = new URL(`${proto}://${host || ip.address()}:${port}/`); + const networkAddress = new URL(`${proto}://${host || getLocalIp()}:${port}/`); if (initialPath) { const searchParams = `?path=${decodeURIComponent( @@ -46,3 +46,10 @@ export const getServerPort = (port?: number, { exactPort }: PortOptions = {}) => export const getServerChannelUrl = (port: number, { https }: { https?: boolean }) => { return `${https ? 'wss' : 'ws'}://localhost:${port}/storybook-server-channel`; }; + +const getLocalIp = () => { + const allIps = Object.values(os.networkInterfaces()).flat(); + const allFilteredIps = allIps.filter((ip) => ip && ip.family === 'IPv4' && !ip.internal); + + return allFilteredIps.length ? allFilteredIps[0]?.address : '0.0.0.0'; +}; diff --git a/code/yarn.lock b/code/yarn.lock index f2edc299accc..60936fb56b7a 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -6051,7 +6051,6 @@ __metadata: "@types/compression": "npm:^1.7.0" "@types/detect-port": "npm:^1.3.0" "@types/diff": "npm:^5.0.9" - "@types/ip": "npm:^1.1.0" "@types/node": "npm:^18.0.0" "@types/node-fetch": "npm:^2.5.7" "@types/pretty-hrtime": "npm:^1.0.0" @@ -6068,7 +6067,6 @@ __metadata: express: "npm:^4.19.2" fs-extra: "npm:^11.1.0" globby: "npm:^14.0.1" - ip: "npm:^2.0.1" lodash: "npm:^4.17.21" node-fetch: "npm:^3.3.1" open: "npm:^8.4.0" @@ -8047,15 +8045,6 @@ __metadata: languageName: node linkType: hard -"@types/ip@npm:^1.1.0": - version: 1.1.3 - resolution: "@types/ip@npm:1.1.3" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/af576e33830196be01b71c48ad5f83380a1c51d62f394a5601e8c2a5b8b31cf6dc8fe71ac39c38d806bcf1d6f1c5c8205c129eca6b6d168c0df7ab3722df23b9 - languageName: node - linkType: hard - "@types/is-empty@npm:^1.0.0": version: 1.2.3 resolution: "@types/is-empty@npm:1.2.3" @@ -17660,7 +17649,7 @@ __metadata: languageName: node linkType: hard -"ip@npm:^2.0.0, ip@npm:^2.0.1": +"ip@npm:^2.0.0": version: 2.0.1 resolution: "ip@npm:2.0.1" checksum: 10c0/cab8eb3e88d0abe23e4724829621ec4c4c5cb41a7f936a2e626c947128c1be16ed543448d42af7cca95379f9892bfcacc1ccd8d09bc7e8bea0e86d492ce33616