feat(context): verify product session scope
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { config } from "../config.js";
|
||||
import type { components } from "../generated/server-api.js";
|
||||
|
||||
export type ProductCredential = {
|
||||
authorization: string;
|
||||
projectId: string;
|
||||
};
|
||||
|
||||
export type AgentAuthContext = components["schemas"]["AgentAuthContextResponse"];
|
||||
|
||||
export class ProductServerClient {
|
||||
constructor(private readonly baseUrl = config.TJWATER_SERVER_BASE_URL) {}
|
||||
|
||||
async authenticate(credential: ProductCredential): Promise<AgentAuthContext> {
|
||||
const url = new URL("/api/v1/agent-auth-context", this.baseUrl);
|
||||
let response: Response;
|
||||
try {
|
||||
response = await fetch(url, {
|
||||
headers: {
|
||||
Accept: "application/json",
|
||||
Authorization: credential.authorization,
|
||||
"X-Project-Id": credential.projectId,
|
||||
},
|
||||
});
|
||||
} catch {
|
||||
throw new ProductServerClientError(503, "TJWater Server unavailable");
|
||||
}
|
||||
|
||||
const text = await response.text();
|
||||
const parsed = parseJson(text);
|
||||
if (!response.ok) {
|
||||
throw new ProductServerClientError(
|
||||
response.status,
|
||||
readErrorMessage(parsed, "TJWater Server rejected identity verification"),
|
||||
);
|
||||
}
|
||||
if (!parsed || typeof parsed !== "object") {
|
||||
throw new ProductServerClientError(502, "TJWater Server returned invalid JSON");
|
||||
}
|
||||
return parsed as AgentAuthContext;
|
||||
}
|
||||
}
|
||||
|
||||
export class ProductServerClientError extends Error {
|
||||
constructor(readonly status: number, message: string) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
const parseJson = (text: string): unknown => {
|
||||
if (!text.trim()) return null;
|
||||
try {
|
||||
return JSON.parse(text);
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const readErrorMessage = (value: unknown, fallback: string) => {
|
||||
if (!value || typeof value !== "object") return fallback;
|
||||
const record = value as Record<string, unknown>;
|
||||
if (typeof record.detail === "string") return record.detail;
|
||||
if (typeof record.message === "string") return record.message;
|
||||
return fallback;
|
||||
};
|
||||
Reference in New Issue
Block a user