98 lines
2.5 KiB
TypeScript
98 lines
2.5 KiB
TypeScript
|
|
import type {
|
||
|
|
ICheckPollResponse,
|
||
|
|
IHeartbeatRequest,
|
||
|
|
IResultSubmitRequest,
|
||
|
|
IUptimeCheckResult,
|
||
|
|
IUptimeRunnerConfig,
|
||
|
|
TCheckJob,
|
||
|
|
} from './interfaces.ts';
|
||
|
|
|
||
|
|
export class UptimeRunnerApiClient {
|
||
|
|
private readonly instanceUrl: URL;
|
||
|
|
private readonly token: string;
|
||
|
|
|
||
|
|
constructor(configArg: IUptimeRunnerConfig) {
|
||
|
|
this.instanceUrl = new URL(configArg.instanceUrl);
|
||
|
|
this.token = configArg.token;
|
||
|
|
}
|
||
|
|
|
||
|
|
public async fetchAssignedChecks(
|
||
|
|
runnerIdArg: string,
|
||
|
|
labelsArg: string[] = [],
|
||
|
|
): Promise<TCheckJob[]> {
|
||
|
|
const url = this.createUrl('/api/runner/v1/checks');
|
||
|
|
url.searchParams.set('runnerId', runnerIdArg);
|
||
|
|
for (const label of labelsArg) {
|
||
|
|
url.searchParams.append('label', label);
|
||
|
|
}
|
||
|
|
|
||
|
|
const responseData = await this.requestJson<ICheckPollResponse | TCheckJob[]>(url, {
|
||
|
|
method: 'GET',
|
||
|
|
});
|
||
|
|
|
||
|
|
if (Array.isArray(responseData)) {
|
||
|
|
return responseData;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (!Array.isArray(responseData.checks)) {
|
||
|
|
throw new Error('Invalid check poll response: expected checks array.');
|
||
|
|
}
|
||
|
|
|
||
|
|
return responseData.checks;
|
||
|
|
}
|
||
|
|
|
||
|
|
public async submitResults(runnerIdArg: string, resultsArg: IUptimeCheckResult[]): Promise<void> {
|
||
|
|
if (resultsArg.length === 0) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
const body: IResultSubmitRequest = {
|
||
|
|
runnerId: runnerIdArg,
|
||
|
|
results: resultsArg,
|
||
|
|
};
|
||
|
|
|
||
|
|
await this.requestJson(this.createUrl('/api/runner/v1/results'), {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(body),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
public async heartbeat(requestArg: IHeartbeatRequest): Promise<void> {
|
||
|
|
await this.requestJson(this.createUrl('/api/runner/v1/heartbeat'), {
|
||
|
|
method: 'POST',
|
||
|
|
body: JSON.stringify(requestArg),
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
private createUrl(pathArg: string): URL {
|
||
|
|
return new URL(pathArg, this.instanceUrl);
|
||
|
|
}
|
||
|
|
|
||
|
|
private async requestJson<T = unknown>(urlArg: URL, initArg: RequestInit): Promise<T> {
|
||
|
|
const response = await fetch(urlArg, {
|
||
|
|
...initArg,
|
||
|
|
headers: {
|
||
|
|
accept: 'application/json',
|
||
|
|
authorization: `Bearer ${this.token}`,
|
||
|
|
'content-type': 'application/json',
|
||
|
|
...(initArg.headers ?? {}),
|
||
|
|
},
|
||
|
|
});
|
||
|
|
|
||
|
|
if (!response.ok) {
|
||
|
|
const body = await response.text().catch(() => '');
|
||
|
|
throw new Error(
|
||
|
|
`uptime.link API ${
|
||
|
|
initArg.method ?? 'GET'
|
||
|
|
} ${urlArg.pathname} failed: ${response.status} ${body}`,
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (response.status === 204) {
|
||
|
|
return undefined as T;
|
||
|
|
}
|
||
|
|
|
||
|
|
return await response.json() as T;
|
||
|
|
}
|
||
|
|
}
|