import { readFileSync } from "node:fs"; import { dirname, resolve } from "node:path"; import type { Environment } from "@mockoon/commons"; import { toErrorMessage } from "../util"; export interface MockServer { url: string; port: number; stop: () => Promise; } /** * Start a Mockoon mock server from a mock.json file. * Returns a handle with the server URL and a stop function. */ export async function createMockServer(mockJsonPath: string, port?: number): Promise { const { MockoonServer, createLoggerInstance, listenServerEvents } = await import("@mockoon/commons-server"); const commons = await import("@mockoon/commons"); const resolvedPath = resolve(mockJsonPath); let parsed: unknown; try { parsed = JSON.parse(readFileSync(resolvedPath, "utf-8")); } catch (err) { throw new Error(`Failed to read mock config "${resolvedPath}": ${toErrorMessage(err)}`); } // EnvironmentSchema is a Joi schema typed as `any` in @mockoon/commons; // it validates the shape and fills in Mockoon defaults const schema = commons.EnvironmentSchema as { validate: ( value: unknown, options?: { abortEarly?: boolean }, ) => { value: Environment; error?: { details: { message: string }[] } }; }; const result = schema.validate(parsed, { abortEarly: false }); if (result.error) { const details = result.error.details.map((d) => d.message).join(", "); throw new Error(`Invalid Mockoon environment "${resolvedPath}": ${details}`); } const environment = result.value; if (port !== undefined) { environment.port = port; } const actualPort = environment.port; const logger = createLoggerInstance(null); const server = new MockoonServer(environment, { environmentDirectory: dirname(resolvedPath), enableAdminApi: false, disableTls: true, enableRandomLatency: false, maxTransactionLogs: 100, envVarsPrefix: "MOCKOON_", }); listenServerEvents(server, environment, logger, false); await new Promise((resolve, reject) => { server.on("started", resolve); server.on("error", (errorCode, originalError) => { reject(originalError ?? new Error(`Mockoon error: ${errorCode}`)); }); server.start(); }); return { url: `http://127.0.0.1:${actualPort}`, port: actualPort, stop: () => new Promise((resolve) => { server.on("stopped", resolve); server.stop(); }), }; }