forked from bai/curriculum-project-hub
feat(hub): capability connection admin API + UI + release v0.0.32 (#8)
Co-authored-by: Hong Jiarong <me@jrhim.com> Co-committed-by: Hong Jiarong <me@jrhim.com>
This commit is contained in:
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* ADR-0027: Capability readiness probe. Validates the Alibaba Cloud docmind
|
||||
* credential by calling QueryDocParserStatus with a dummy id — a 400 (bad
|
||||
* request) means the credential is valid (the API accepted auth but rejected
|
||||
* the id); a 401/403 means the credential is bad.
|
||||
*/
|
||||
import { classifyNetworkFailure, type NetworkFailureCategory } from "../connections/networkFailure.js";
|
||||
|
||||
export interface CapabilityReadinessInput {
|
||||
readonly endpoint: string;
|
||||
readonly accessKeyId: string;
|
||||
readonly accessKeySecret: string;
|
||||
}
|
||||
|
||||
export type CapabilityReadinessProbe = (input: CapabilityReadinessInput) => Promise<void>;
|
||||
|
||||
export class CapabilityReadinessError extends Error {
|
||||
constructor(
|
||||
readonly code: "capability_readiness_unsupported" | "capability_readiness_unreachable" | "capability_readiness_rejected",
|
||||
message: string,
|
||||
readonly category: NetworkFailureCategory | "configuration" | "http",
|
||||
readonly upstreamStatus?: number,
|
||||
) {
|
||||
super(message);
|
||||
this.name = "CapabilityReadinessError";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Probe the Alibaba Cloud docmind credential. We call QueryDocParserStatus
|
||||
* with a dummy id. The API will return:
|
||||
* - 400 (InvalidParameter) → credential valid, just a bad id → probe passes
|
||||
* - 401/403 (InvalidAccessKey/Forbidden) → credential invalid → probe fails
|
||||
* - network error → unreachable
|
||||
*/
|
||||
export const probeDocmindCredential: CapabilityReadinessProbe = async (input) => {
|
||||
const url = `https://${input.endpoint}/?Action=QueryDocParserStatus&Id=probe-test&Version=2022-07-11`;
|
||||
const authHeader = makeBasicAuth(input.accessKeyId, input.accessKeySecret);
|
||||
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(url, {
|
||||
method: "GET",
|
||||
headers: { authorization: authHeader, accept: "application/json" },
|
||||
redirect: "manual",
|
||||
signal: AbortSignal.timeout(10_000),
|
||||
});
|
||||
} catch (error) {
|
||||
throw new CapabilityReadinessError(
|
||||
"capability_readiness_unreachable",
|
||||
"docmind credential readiness check could not reach the API",
|
||||
classifyNetworkFailure(error),
|
||||
);
|
||||
}
|
||||
await response.body?.cancel();
|
||||
if (response.status === 401 || response.status === 403) {
|
||||
throw new CapabilityReadinessError(
|
||||
"capability_readiness_rejected",
|
||||
`docmind credential rejected: status ${response.status}`,
|
||||
"http",
|
||||
response.status,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
function makeBasicAuth(accessKeyId: string, accessKeySecret: string): string {
|
||||
const credentials = Buffer.from(`${accessKeyId}:${accessKeySecret}`).toString("base64");
|
||||
return `Basic ${credentials}`;
|
||||
}
|
||||
Reference in New Issue
Block a user