gc-wing/apps/web/src/entities/aisTarget/api/searchAisTargets.ts

39 lines
1.4 KiB
TypeScript
Raw Normal View 히스토리

2026-02-15 11:22:38 +09:00
import type { AisTargetSearchResponse } from "../model/types";
export type SearchAisTargetsParams = {
minutes: number;
bbox?: string;
};
export async function searchAisTargets(params: SearchAisTargetsParams, signal?: AbortSignal) {
// Same convention as the "dark" project:
// - dev: default to Vite proxy base `/snp-api`
// - prod/other: can be overridden via `VITE_API_URL` (e.g. `http://host:8041/snp-api`)
const base = (import.meta.env.VITE_API_URL || "/snp-api").replace(/\/$/, "");
const u = new URL(`${base}/api/ais-target/search`, window.location.origin);
u.searchParams.set("minutes", String(params.minutes));
if (params.bbox) u.searchParams.set("bbox", params.bbox);
const res = await fetch(u, { signal, headers: { accept: "application/json" } });
const txt = await res.text();
let json: unknown = null;
try {
json = JSON.parse(txt);
} catch {
// ignore
}
if (!res.ok) {
const msg =
json && typeof json === "object" && typeof (json as { message?: unknown }).message === "string"
? (json as { message: string }).message
: txt.slice(0, 200) || res.statusText;
throw new Error(`AIS target API failed: ${res.status} ${msg}`);
}
if (!json || typeof json !== "object") throw new Error("AIS target API returned invalid payload");
const parsed = json as AisTargetSearchResponse;
if (!parsed.success) throw new Error(parsed.message || "AIS target API returned success=false");
return parsed;
}