feat: add uptime runner agent
This commit is contained in:
@@ -0,0 +1,97 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user