@roots/bud-api
Version:
bud.js core module
124 lines (107 loc) • 3.13 kB
text/typescript
import type {Bud, Server} from '@roots/bud-framework'
import {
portOrPortsToNumbers,
requestPorts,
} from '@roots/bud-support/get-port'
import isArray from '@roots/bud-support/isArray'
import isEqual from '@roots/bud-support/isEqual'
import isNumber from '@roots/bud-support/isNumber'
import isString from '@roots/bud-support/isString'
import isUndefined from '@roots/bud-support/isUndefined'
import type {Options, Parameters, ServerOptions} from './serve.types.js'
/**
* bud.serve
*/
export interface serve {
(...parameters: Parameters): Promise<Bud>
}
export type {Options, Parameters, ServerOptions}
/**
* bud.serve
*/
export const serve: serve = async function (this: Bud, input, options) {
const bud = this.root
if (!bud.isDevelopment) return bud
if (!bud?.server) return bud
let normalizedUrl = input instanceof URL ? input : bud.server.url
let normalizedOptions = options ?? bud.hooks.filter(`dev.options`, {})
/**
* If input is a string, convert it to a {@link URL}
*/
if (isString(input)) normalizedUrl = new URL(input)
/**
* If input is a number or array of numbers,
* try to resolve the requested port(s) and
* assign to the {@link URL}
*/
if (isArray(input) || isNumber(input)) {
normalizedUrl.port = await requestPorts(
portOrPortsToNumbers(bud.context.port ?? input),
)
}
/**
* If input is an object, convert it to a {@link URL}
* and {@link ServerOptions}
*/
if (
!(input instanceof URL) &&
!isArray(input) &&
typeof input === `object`
) {
normalizedUrl = await makeURLFromObject(bud, input, normalizedUrl)
normalizedOptions = await makeHttpOptions(
bud,
input,
normalizedOptions,
)
}
bud.hooks.on(`dev.url`, normalizedUrl)
bud.hooks.on(`dev.options`, normalizedOptions)
return bud
}
/**
* Process specification object
*/
const makeURLFromObject = async function (
bud: Bud,
options: Options,
url: Server[`url`],
): Promise<Server[`url`]> {
if (options.url) {
return options.url instanceof URL ? options.url : new URL(options.url)
}
if (options.host) url.hostname = options.host
if (options.port)
url.port = await requestPorts(portOrPortsToNumbers(options.port))
if (
url.protocol !== `https:` &&
[
!isUndefined(options.ssl),
!isUndefined(options.cert),
!isUndefined(options.key),
!isUndefined(options?.options?.cert),
!isUndefined(options?.options?.key),
isEqual(url.port, 443),
].some(Boolean)
)
url.protocol = `https:`
return url
}
/**
* Make ServerOptions from object
*
* @param bud - {@link Bud}
* @param input - {@link Options}
* @param resolvedOptions - {@link Options}
* @returns promise - {@link ServerOptions}
*/
const makeHttpOptions = async function (
bud: Bud,
input: Options,
resolvedOptions: ServerOptions = {},
): Promise<ServerOptions> {
if (input.options) resolvedOptions = input.options
if (input.cert) resolvedOptions.cert = await bud.fs.read(input.cert)
if (input.key) resolvedOptions.key = await bud.fs.read(input.key)
return resolvedOptions
}