@kya-os/agentshield-nextjs
Version:
Next.js middleware for AgentShield AI agent detection
196 lines (195 loc) • 6.33 kB
JavaScript
// src/api-client.ts
var DEFAULT_BASE_URL = "https://kya.vouched.id";
var EDGE_DETECT_URL = "https://detect.checkpoint-gateway.ai";
var DEFAULT_TIMEOUT = 5e3;
var AgentShieldClient = class {
apiKey;
baseUrl;
useEdge;
timeout;
debug;
constructor(config) {
if (!config.apiKey) {
throw new Error("AgentShield API key is required");
}
this.apiKey = config.apiKey;
this.useEdge = config.useEdge !== false;
this.baseUrl = config.baseUrl || (this.useEdge ? EDGE_DETECT_URL : DEFAULT_BASE_URL);
this.timeout = config.timeout || DEFAULT_TIMEOUT;
this.debug = config.debug || false;
}
/**
* Call the enforce API to check if a request should be allowed
*/
async enforce(input) {
const startTime = Date.now();
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const endpoint = this.useEdge ? `${this.baseUrl}/__detect/enforce` : `${this.baseUrl}/api/v1/enforce`;
const response = await fetch(endpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.apiKey}`,
"X-Request-ID": input.requestId || crypto.randomUUID()
},
body: JSON.stringify(input),
signal: controller.signal
});
clearTimeout(timeoutId);
const data = await response.json();
if (this.debug) {
console.log("[AgentShield] Enforce response:", {
status: response.status,
action: data.data?.decision.action,
processingTimeMs: Date.now() - startTime
});
}
if (!response.ok) {
return {
success: false,
error: {
code: `HTTP_${response.status}`,
message: data.error?.message || `HTTP error: ${response.status}`
}
};
}
return data;
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
} catch (error) {
if (error instanceof Error && error.name === "AbortError") {
if (this.debug) {
console.warn("[AgentShield] Request timed out");
}
return {
success: false,
error: {
code: "TIMEOUT",
message: `Request timed out after ${this.timeout}ms`
}
};
}
if (this.debug) {
console.error("[AgentShield] Request failed:", error);
}
return {
success: false,
error: {
code: "NETWORK_ERROR",
message: error instanceof Error ? error.message : "Network request failed"
}
};
}
}
/**
* Quick check - returns just the action without full response parsing
* Useful for very fast middleware that just needs allow/block
*/
async quickCheck(input) {
const result = await this.enforce(input);
if (!result.success || !result.data) {
return {
action: "allow",
error: result.error?.message
};
}
return {
action: result.data.decision.action
};
}
/**
* Check if this client is using edge detection (Gateway Worker)
*/
isUsingEdge() {
return this.useEdge;
}
/**
* Log a detection result to AgentShield database.
* Use after Gateway Worker detection to persist results.
* Fire-and-forget - returns immediately without waiting for DB write.
*
* @example
* ```typescript
* // After receiving Gateway response
* if (client.isUsingEdge() && response.data?.detection) {
* client.logDetection({
* detection: response.data.detection,
* context: { userAgent, ipAddress, path, url, method }
* }).catch(err => console.error('Log failed:', err));
* }
* ```
*/
async logDetection(input) {
const logEndpoint = this.useEdge ? `${DEFAULT_BASE_URL}/api/v1/log-detection` : `${this.baseUrl}/api/v1/log-detection`;
try {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(logEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${this.apiKey}`
},
body: JSON.stringify({
detection: {
isAgent: input.detection.isAgent,
confidence: input.detection.confidence,
agentName: input.detection.agentName,
agentType: input.detection.agentType,
detectionClass: input.detection.detectionClass,
verificationMethod: input.detection.verificationMethod,
reasons: input.detection.reasons
},
context: input.context,
source: input.source || "gateway"
}),
signal: controller.signal
});
clearTimeout(timeoutId);
if (!response.ok && this.debug) {
console.warn("[AgentShield] Log detection returned non-2xx:", response.status);
}
} catch (error) {
clearTimeout(timeoutId);
throw error;
}
} catch (error) {
if (this.debug) {
console.error("[AgentShield] Log detection failed:", error);
}
throw error;
}
}
};
var clientInstance = null;
function getAgentShieldClient(config) {
if (!clientInstance) {
const apiKey = config?.apiKey || process.env.AGENTSHIELD_API_KEY;
if (!apiKey) {
throw new Error(
"AgentShield API key is required. Set AGENTSHIELD_API_KEY environment variable or pass apiKey in config."
);
}
clientInstance = new AgentShieldClient({
apiKey,
baseUrl: config?.baseUrl || process.env.AGENTSHIELD_API_URL,
// Default to edge detection unless explicitly disabled
useEdge: config?.useEdge ?? process.env.AGENTSHIELD_USE_EDGE !== "false",
timeout: config?.timeout,
debug: config?.debug || process.env.AGENTSHIELD_DEBUG === "true"
});
}
return clientInstance;
}
function resetAgentShieldClient() {
clientInstance = null;
}
export { AgentShieldClient, getAgentShieldClient, resetAgentShieldClient };
//# sourceMappingURL=api-client.mjs.map
//# sourceMappingURL=api-client.mjs.map