96 lines
2.6 KiB
TypeScript
96 lines
2.6 KiB
TypeScript
import type { BatchPayload } from "../content/market/batch-payload";
|
|
import { isAuthResponseMessage } from "./auth-messages";
|
|
import { DEFAULT_BATCH_SUBMIT_BASE_URL } from "./batch-submit-config";
|
|
|
|
interface FetchResponseLike {
|
|
json(): Promise<unknown>;
|
|
ok: boolean;
|
|
status: number;
|
|
}
|
|
|
|
type FetchLike = (
|
|
input: string,
|
|
init?: RequestInit
|
|
) => Promise<FetchResponseLike>;
|
|
|
|
type GetAccessTokenLike = () => Promise<string>;
|
|
type SendMessageLike = (message: unknown) => Promise<unknown>;
|
|
|
|
export function createBatchSubmitClient(options: {
|
|
baseUrl?: string;
|
|
fetchImpl?: FetchLike;
|
|
getAccessToken?: GetAccessTokenLike;
|
|
sendMessage: SendMessageLike;
|
|
}) {
|
|
const baseUrl = options.baseUrl ?? DEFAULT_BATCH_SUBMIT_BASE_URL;
|
|
const fetchImpl = options.fetchImpl ?? fetch;
|
|
const getAccessToken =
|
|
options.getAccessToken ?? (() => readAccessToken(options.sendMessage));
|
|
|
|
return {
|
|
async submitBatch(payload: BatchPayload) {
|
|
const token = await getAccessToken();
|
|
const response = await fetchImpl(
|
|
buildBatchSubmitUrl(baseUrl),
|
|
{
|
|
body: JSON.stringify(payload),
|
|
headers: {
|
|
Authorization: `Bearer ${token}`,
|
|
"Content-Type": "application/json"
|
|
},
|
|
method: "POST"
|
|
}
|
|
);
|
|
|
|
if (response.status === 401 || response.status === 403) {
|
|
throw new Error("batch submit unauthorized");
|
|
}
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`batch submit failed: ${response.status}`);
|
|
}
|
|
|
|
return readBatchSubmitResponse(await response.json());
|
|
}
|
|
};
|
|
}
|
|
|
|
export function buildBatchSubmitUrl(baseUrl: string): string {
|
|
return new URL("/api/v1/batch-status/batches", baseUrl).toString();
|
|
}
|
|
|
|
async function readAccessToken(sendMessage: SendMessageLike): Promise<string> {
|
|
const response = await sendMessage({ type: "auth:get-access-token" });
|
|
|
|
if (
|
|
!isAuthResponseMessage(response) ||
|
|
!response.ok ||
|
|
response.type !== "auth:token" ||
|
|
!response.value.accessToken.trim()
|
|
) {
|
|
throw new Error("batch submit token unavailable");
|
|
}
|
|
|
|
return response.value.accessToken;
|
|
}
|
|
|
|
function readBatchSubmitResponse(payload: unknown): unknown {
|
|
if (!isRecord(payload)) {
|
|
throw new Error("batch submit response is invalid");
|
|
}
|
|
|
|
if (payload.success !== true) {
|
|
const message =
|
|
typeof payload.msg === "string" && payload.msg.trim()
|
|
? payload.msg
|
|
: "batch submit failed";
|
|
throw new Error(message);
|
|
}
|
|
|
|
return "data" in payload ? payload.data : payload;
|
|
}
|
|
|
|
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
return typeof value === "object" && value !== null;
|
|
}
|