deadhead-space-freight-tycoon/apps/web/src/api/engine-client.ts

35 lines
1.3 KiB
TypeScript

import { CommandError, NOT_FOUND_CODES, type CommandName, type GameEngine } from "@deadhead/engine";
import type { RouteName } from "@deadhead/schema";
import { ApiError, type ApiClient } from "./client";
/** The HTTP status the server sent for a code, so screens read refusals as before. */
function statusFor(code: CommandError["code"]): number {
if (code === "validation-error") return 400;
if (code === "unauthorized") return 401;
return NOT_FOUND_CODES.has(code) ? 404 : 409;
}
/**
* The typed client over the engine instead of HTTP (CR-014 Step 14.7): the
* same catalog names, inputs and outputs, and refusals as the same `ApiError`s.
*/
export function createEngineClient(engine: GameEngine): ApiClient {
let prompt: Promise<void> = Promise.resolve();
return {
async call(name, input) {
try {
const result = await engine.call(name as RouteName as CommandName, input as never);
// Notifications are asked for once the player owns the business (decision 0.5.91).
if (name === "acceptDeal") prompt = engine.requestNotificationPermission().catch(() => {});
return result as never;
} catch (error) {
if (error instanceof CommandError) {
throw new ApiError(statusFor(error.code), error.code, error.message);
}
throw error;
}
},
notificationPrompt: () => prompt,
};
}