Skip to content
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
76 changes: 0 additions & 76 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@
"ulid": "3.0.1",
"update-notifier": "7.3.1",
"uuid": "11.1.0",
"wait-port": "1.1.0",
"write-file-atomic": "5.0.1",
"ws": "8.18.3"
},
Expand Down
15 changes: 7 additions & 8 deletions src/lib/http-agent.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { readFile } from 'fs/promises'

import { HttpsProxyAgent } from 'https-proxy-agent'
import waitPort from 'wait-port'

import { NETLIFYDEVERR, NETLIFYDEVWARN, exit, log } from '../utils/command-helpers.js'
import { waitPort } from './wait-port.js'

// https://github.com/TooTallNate/node-https-proxy-agent/issues/89
// Maybe replace with https://github.com/delvedor/hpagent
Expand All @@ -29,7 +29,7 @@ class HttpsProxyAgentWithCA extends HttpsProxyAgent {
const DEFAULT_HTTP_PORT = 80
const DEFAULT_HTTPS_PORT = 443
// 50 seconds
const AGENT_PORT_TIMEOUT = 50
const AGENT_PORT_TIMEOUT = 50_000

export const tryGetAgent = async ({
certificateFile,
Expand Down Expand Up @@ -66,12 +66,11 @@ export const tryGetAgent = async ({

let port
try {
port = await waitPort({
port: Number.parseInt(proxyUrl.port) || (scheme === 'http' ? DEFAULT_HTTP_PORT : DEFAULT_HTTPS_PORT),
host: proxyUrl.hostname,
timeout: AGENT_PORT_TIMEOUT,
output: 'silent',
})
port = await waitPort(
Number.parseInt(proxyUrl.port) || (scheme === 'http' ? DEFAULT_HTTP_PORT : DEFAULT_HTTPS_PORT),
proxyUrl.hostname,
AGENT_PORT_TIMEOUT,
)
} catch (error) {
// unknown error
// @ts-expect-error TS(2571) FIXME: Object is of type 'unknown'.
Expand Down
57 changes: 57 additions & 0 deletions src/lib/wait-port.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import net from 'net'

export const waitPort = async (
port: number,
host: string,
timeout: number,
maxRetries?: number,
): Promise<{ open: boolean; ipVersion?: 4 | 6 }> => {
const startTime = Date.now()
const retries = maxRetries ?? Math.ceil(timeout / 2000)

for (let attempt = 0; attempt < retries; attempt++) {
if (Date.now() - startTime > timeout) {
return { open: false }
}

try {
const ipVersion = await new Promise<4 | 6>((resolve, reject) => {
const socket = new net.Socket()
let isResolved = false

socket.on('connect', () => {
isResolved = true
// Detect actual IP version from the connection
const detectedVersion = socket.remoteFamily === 'IPv6' ? 6 : 4
socket.end()
resolve(detectedVersion)
})

socket.on('error', (error) => {
if (!isResolved) {
isResolved = true
socket.destroy()
reject(error)
}
})

socket.setTimeout(1000, () => {
if (!isResolved) {
isResolved = true
socket.destroy()
reject(new Error('Socket timeout'))
}
})

socket.connect(port, host)
})

return { open: true, ipVersion }
} catch {
await new Promise((resolve) => setTimeout(resolve, Math.min(100 * (attempt + 1), 1000)))
continue
}
}

return { open: false }
}
16 changes: 7 additions & 9 deletions src/utils/framework-server.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { rm } from 'node:fs/promises'

import waitPort from 'wait-port'

import { startSpinner, stopSpinner } from '../lib/spinner.js'
import { waitPort } from '../lib/wait-port.js'

import { logAndThrowError, log, NETLIFYDEVERR, NETLIFYDEVLOG, chalk } from './command-helpers.js'
import { runCommand } from './shell.js'
Expand Down Expand Up @@ -56,14 +55,13 @@ export const startFrameworkServer = async function ({
const ipVersion = parseInt(process.versions.node.split('.')[0]) >= 18 ? 6 : 4
port = { open: true, ipVersion }
} else {
const waitPortPromise = waitPort({
const waitPortPromise = waitPort(
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
port: settings.frameworkPort!,
host: 'localhost',
output: 'silent',
timeout: FRAMEWORK_PORT_TIMEOUT_MS,
...(settings.pollingStrategies?.includes('HTTP') && { protocol: 'http' }),
Copy link
Member

Choose a reason for hiding this comment

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

I was worried about this removal but I think it works out:

So... I think it works out. But we should remove pollingStrategies from @netlify/build-info.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

should be done by a maintainer after the merge as its just info

})
settings.frameworkPort!,
'localhost',
FRAMEWORK_PORT_TIMEOUT_MS,
20,
)

const timerId = setTimeout(() => {
if (!port?.open) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import getPort from 'get-port'
import fetch from 'node-fetch'
import semver from 'semver'
import { describe, test } from 'vitest'
import waitPort from 'wait-port'

import { waitPort } from '../../../../src/lib/wait-port.js'
import { cliPath } from '../../utils/cli-path.js'
import { withMockApi } from '../../utils/mock-api.js'
import { type SiteBuilder, withSiteBuilder } from '../../utils/site-builder.js'
Expand Down Expand Up @@ -48,12 +48,8 @@ const withFunctionsServer = async (
console.log(data.toString())
})

const { open } = await waitPort({
port,
output: 'silent',
timeout: SERVE_TIMEOUT,
})
if (!open) {
const result = await waitPort(port, 'localhost', SERVE_TIMEOUT)
if (!result.open) {
throw new Error('Timed out waiting for functions server')
}
return await testHandler()
Expand Down
Loading