2Branches0Tags
GL
glucryptoFix trade candle loading via gateway
typescript
function parseJson(raw: string | null): unknown | null { if (!raw) return null; try { return JSON.parse(raw) as unknown; } catch { return null; } } type OpenpondAppListEntry = { id?: string; gitRepo?: string | null; repo?: string | null; name?: string | null; latestDeployment?: { id?: string; status?: string | null; } | null; }; type OpenpondExecuteEnvelope = { ok?: unknown; status?: unknown; data?: unknown; error?: unknown; }; function resolveBaseUrl() { const baseUrl = process.env.BASE_URL; if (!baseUrl) { throw new Error("BASE_URL is required for My OpenPond."); } return baseUrl.replace(/\/$/, ""); } async function fetchJson( url: string, options: RequestInit, ): Promise<{ ok: boolean; status: number; data: unknown | null }> { const response = await fetch(url, options); const text = await response.text(); const data = parseJson(text); return { ok: response.ok, status: response.status, data }; } export async function openpondRequest(path: string, options: RequestInit) { const apiKey = process.env.OPENPOND_API_KEY; if (!apiKey) { throw new Error("OPENPOND_API_KEY is required for My OpenPond."); } const url = `${resolveBaseUrl()}${path}`; const headers = new Headers(options.headers ?? {}); headers.set("openpond-api-key", apiKey); if (!headers.has("Authorization")) { headers.set("Authorization", `ApiKey ${apiKey}`); } return fetchJson(url, { ...options, headers }); } function resolveGatewayUrl() { const gatewayUrl = process.env.OPENPOND_GATEWAY_URL; if (!gatewayUrl) { throw new Error("OPENPOND_GATEWAY_URL is required for My OpenPond."); } return gatewayUrl.replace(/\/$/, ""); } export async function gatewayRequest(path: string, options: RequestInit) { const url = `${resolveGatewayUrl()}${path}`; const headers = new Headers(options.headers ?? {}); return fetchJson(url, { ...options, headers }); } function normalizeRepoName(value: string | null | undefined) { return (value ?? "").trim().toLowerCase(); } function isRecord(value: unknown): value is Record<string, unknown> { return Boolean(value) && typeof value === "object" && !Array.isArray(value); } function isExecuteEnvelope(value: unknown): value is OpenpondExecuteEnvelope { if (!isRecord(value)) return false; return "data" in value || "error" in value || "status" in value; } export function unwrapOpenpondExecuteResponse(response: { ok: boolean; status: number; data: unknown | null; }): { ok: boolean; status: number; data: unknown | null; error: string | null; } { let ok = response.ok; let status = response.status; let current: unknown | null = response.data; let error: string | null = null; while (isExecuteEnvelope(current)) { if (typeof current.ok === "boolean") { ok = ok && current.ok; } if (typeof current.status === "number") { status = current.status; } if (typeof current.error === "string" && current.error.trim().length > 0) { error = current.error; } if (!("data" in current)) { current = null; break; } current = current.data ?? null; } return { ok, status, data: current, error }; } export async function resolveLatestAppDeploymentByRepoName(repoName: string): Promise<{ appId: string; deploymentId: string; } | null> { const response = await openpondRequest("/apps/list", { method: "GET", headers: { Accept: "application/json" }, }); if (!response.ok || !response.data || typeof response.data !== "object") { return null; } const apps = Array.isArray((response.data as { apps?: unknown[] }).apps) ? ((response.data as { apps?: unknown[] }).apps as unknown[]) : []; const normalizedRepo = normalizeRepoName(repoName); for (const candidate of apps) { if (!candidate || typeof candidate !== "object" || Array.isArray(candidate)) { continue; } const record = candidate as OpenpondAppListEntry; const matchesRepo = normalizeRepoName(record.gitRepo) === normalizedRepo || normalizeRepoName(record.repo) === normalizedRepo || normalizeRepoName(record.name) === normalizedRepo; if (!matchesRepo) continue; const appId = typeof record.id === "string" ? record.id.trim() : ""; const deploymentId = typeof record.latestDeployment?.id === "string" ? record.latestDeployment.id.trim() : ""; if (!appId || !deploymentId) continue; return { appId, deploymentId }; } return null; }