@kya-os/agentshield-nextjs 0.2.9 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api-client.d.mts +41 -1
- package/dist/api-client.d.ts +41 -1
- package/dist/api-client.js +64 -0
- package/dist/api-client.js.map +1 -1
- package/dist/api-client.mjs +64 -0
- package/dist/api-client.mjs.map +1 -1
- package/dist/api-middleware.js +100 -14
- package/dist/api-middleware.js.map +1 -1
- package/dist/api-middleware.mjs +100 -14
- package/dist/api-middleware.mjs.map +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +100 -14
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +100 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +22 -21
- package/wasm/agentshield_wasm.d.ts +379 -21
- package/wasm/agentshield_wasm.js +1409 -506
- package/wasm/agentshield_wasm_bg.wasm +0 -0
- package/dist/.tsbuildinfo +0 -1
package/dist/api-client.d.mts
CHANGED
|
@@ -59,6 +59,8 @@ interface DetectionResult {
|
|
|
59
59
|
confidence: number;
|
|
60
60
|
agentName?: string;
|
|
61
61
|
agentType?: string;
|
|
62
|
+
/** Detection class: 'human', 'ai_agent', 'bot', 'incomplete_data' */
|
|
63
|
+
detectionClass?: string;
|
|
62
64
|
verificationMethod?: string;
|
|
63
65
|
reasons?: string[];
|
|
64
66
|
/** Detection engine used: 'wasm' or 'javascript-fallback' */
|
|
@@ -106,6 +108,23 @@ interface EnforceInput {
|
|
|
106
108
|
cacheTTL?: number;
|
|
107
109
|
};
|
|
108
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Input for logging a detection result
|
|
113
|
+
*/
|
|
114
|
+
interface LogDetectionInput {
|
|
115
|
+
/** Detection result from Gateway */
|
|
116
|
+
detection: DetectionResult;
|
|
117
|
+
/** Request context */
|
|
118
|
+
context: {
|
|
119
|
+
userAgent?: string;
|
|
120
|
+
ipAddress?: string;
|
|
121
|
+
path?: string;
|
|
122
|
+
url?: string;
|
|
123
|
+
method?: string;
|
|
124
|
+
};
|
|
125
|
+
/** Source of the detection */
|
|
126
|
+
source?: 'gateway' | 'middleware';
|
|
127
|
+
}
|
|
109
128
|
/**
|
|
110
129
|
* AgentShield API Client
|
|
111
130
|
*
|
|
@@ -145,6 +164,27 @@ declare class AgentShieldClient {
|
|
|
145
164
|
action: EnforcementAction;
|
|
146
165
|
error?: string;
|
|
147
166
|
}>;
|
|
167
|
+
/**
|
|
168
|
+
* Check if this client is using edge detection (Gateway Worker)
|
|
169
|
+
*/
|
|
170
|
+
isUsingEdge(): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Log a detection result to AgentShield database.
|
|
173
|
+
* Use after Gateway Worker detection to persist results.
|
|
174
|
+
* Fire-and-forget - returns immediately without waiting for DB write.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* // After receiving Gateway response
|
|
179
|
+
* if (client.isUsingEdge() && response.data?.detection) {
|
|
180
|
+
* client.logDetection({
|
|
181
|
+
* detection: response.data.detection,
|
|
182
|
+
* context: { userAgent, ipAddress, path, url, method }
|
|
183
|
+
* }).catch(err => console.error('Log failed:', err));
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
logDetection(input: LogDetectionInput): Promise<void>;
|
|
148
188
|
}
|
|
149
189
|
declare function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>): AgentShieldClient;
|
|
150
190
|
/**
|
|
@@ -152,4 +192,4 @@ declare function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>)
|
|
|
152
192
|
*/
|
|
153
193
|
declare function resetAgentShieldClient(): void;
|
|
154
194
|
|
|
155
|
-
export { AgentShieldClient, type AgentShieldClientConfig, type DetectionResult, type EnforceInput, type EnforceResponse, type EnforcementAction, type EnforcementDecision, getAgentShieldClient, resetAgentShieldClient };
|
|
195
|
+
export { AgentShieldClient, type AgentShieldClientConfig, type DetectionResult, type EnforceInput, type EnforceResponse, type EnforcementAction, type EnforcementDecision, type LogDetectionInput, getAgentShieldClient, resetAgentShieldClient };
|
package/dist/api-client.d.ts
CHANGED
|
@@ -59,6 +59,8 @@ interface DetectionResult {
|
|
|
59
59
|
confidence: number;
|
|
60
60
|
agentName?: string;
|
|
61
61
|
agentType?: string;
|
|
62
|
+
/** Detection class: 'human', 'ai_agent', 'bot', 'incomplete_data' */
|
|
63
|
+
detectionClass?: string;
|
|
62
64
|
verificationMethod?: string;
|
|
63
65
|
reasons?: string[];
|
|
64
66
|
/** Detection engine used: 'wasm' or 'javascript-fallback' */
|
|
@@ -106,6 +108,23 @@ interface EnforceInput {
|
|
|
106
108
|
cacheTTL?: number;
|
|
107
109
|
};
|
|
108
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Input for logging a detection result
|
|
113
|
+
*/
|
|
114
|
+
interface LogDetectionInput {
|
|
115
|
+
/** Detection result from Gateway */
|
|
116
|
+
detection: DetectionResult;
|
|
117
|
+
/** Request context */
|
|
118
|
+
context: {
|
|
119
|
+
userAgent?: string;
|
|
120
|
+
ipAddress?: string;
|
|
121
|
+
path?: string;
|
|
122
|
+
url?: string;
|
|
123
|
+
method?: string;
|
|
124
|
+
};
|
|
125
|
+
/** Source of the detection */
|
|
126
|
+
source?: 'gateway' | 'middleware';
|
|
127
|
+
}
|
|
109
128
|
/**
|
|
110
129
|
* AgentShield API Client
|
|
111
130
|
*
|
|
@@ -145,6 +164,27 @@ declare class AgentShieldClient {
|
|
|
145
164
|
action: EnforcementAction;
|
|
146
165
|
error?: string;
|
|
147
166
|
}>;
|
|
167
|
+
/**
|
|
168
|
+
* Check if this client is using edge detection (Gateway Worker)
|
|
169
|
+
*/
|
|
170
|
+
isUsingEdge(): boolean;
|
|
171
|
+
/**
|
|
172
|
+
* Log a detection result to AgentShield database.
|
|
173
|
+
* Use after Gateway Worker detection to persist results.
|
|
174
|
+
* Fire-and-forget - returns immediately without waiting for DB write.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* ```typescript
|
|
178
|
+
* // After receiving Gateway response
|
|
179
|
+
* if (client.isUsingEdge() && response.data?.detection) {
|
|
180
|
+
* client.logDetection({
|
|
181
|
+
* detection: response.data.detection,
|
|
182
|
+
* context: { userAgent, ipAddress, path, url, method }
|
|
183
|
+
* }).catch(err => console.error('Log failed:', err));
|
|
184
|
+
* }
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
logDetection(input: LogDetectionInput): Promise<void>;
|
|
148
188
|
}
|
|
149
189
|
declare function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>): AgentShieldClient;
|
|
150
190
|
/**
|
|
@@ -152,4 +192,4 @@ declare function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>)
|
|
|
152
192
|
*/
|
|
153
193
|
declare function resetAgentShieldClient(): void;
|
|
154
194
|
|
|
155
|
-
export { AgentShieldClient, type AgentShieldClientConfig, type DetectionResult, type EnforceInput, type EnforceResponse, type EnforcementAction, type EnforcementDecision, getAgentShieldClient, resetAgentShieldClient };
|
|
195
|
+
export { AgentShieldClient, type AgentShieldClientConfig, type DetectionResult, type EnforceInput, type EnforceResponse, type EnforcementAction, type EnforcementDecision, type LogDetectionInput, getAgentShieldClient, resetAgentShieldClient };
|
package/dist/api-client.js
CHANGED
|
@@ -104,6 +104,70 @@ var AgentShieldClient = class {
|
|
|
104
104
|
action: result.data.decision.action
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* Check if this client is using edge detection (Gateway Worker)
|
|
109
|
+
*/
|
|
110
|
+
isUsingEdge() {
|
|
111
|
+
return this.useEdge;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Log a detection result to AgentShield database.
|
|
115
|
+
* Use after Gateway Worker detection to persist results.
|
|
116
|
+
* Fire-and-forget - returns immediately without waiting for DB write.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```typescript
|
|
120
|
+
* // After receiving Gateway response
|
|
121
|
+
* if (client.isUsingEdge() && response.data?.detection) {
|
|
122
|
+
* client.logDetection({
|
|
123
|
+
* detection: response.data.detection,
|
|
124
|
+
* context: { userAgent, ipAddress, path, url, method }
|
|
125
|
+
* }).catch(err => console.error('Log failed:', err));
|
|
126
|
+
* }
|
|
127
|
+
* ```
|
|
128
|
+
*/
|
|
129
|
+
async logDetection(input) {
|
|
130
|
+
const logEndpoint = this.useEdge ? `${DEFAULT_BASE_URL}/api/v1/log-detection` : `${this.baseUrl}/api/v1/log-detection`;
|
|
131
|
+
try {
|
|
132
|
+
const controller = new AbortController();
|
|
133
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
134
|
+
try {
|
|
135
|
+
const response = await fetch(logEndpoint, {
|
|
136
|
+
method: "POST",
|
|
137
|
+
headers: {
|
|
138
|
+
"Content-Type": "application/json",
|
|
139
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
140
|
+
},
|
|
141
|
+
body: JSON.stringify({
|
|
142
|
+
detection: {
|
|
143
|
+
isAgent: input.detection.isAgent,
|
|
144
|
+
confidence: input.detection.confidence,
|
|
145
|
+
agentName: input.detection.agentName,
|
|
146
|
+
agentType: input.detection.agentType,
|
|
147
|
+
detectionClass: input.detection.detectionClass,
|
|
148
|
+
verificationMethod: input.detection.verificationMethod,
|
|
149
|
+
reasons: input.detection.reasons
|
|
150
|
+
},
|
|
151
|
+
context: input.context,
|
|
152
|
+
source: input.source || "gateway"
|
|
153
|
+
}),
|
|
154
|
+
signal: controller.signal
|
|
155
|
+
});
|
|
156
|
+
clearTimeout(timeoutId);
|
|
157
|
+
if (!response.ok && this.debug) {
|
|
158
|
+
console.warn("[AgentShield] Log detection returned non-2xx:", response.status);
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
clearTimeout(timeoutId);
|
|
162
|
+
throw error;
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
if (this.debug) {
|
|
166
|
+
console.error("[AgentShield] Log detection failed:", error);
|
|
167
|
+
}
|
|
168
|
+
throw error;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
107
171
|
};
|
|
108
172
|
var clientInstance = null;
|
|
109
173
|
function getAgentShieldClient(config) {
|
package/dist/api-client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api-client.ts"],"names":[],"mappings":"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","file":"api-client.js","sourcesContent":["/**\n * AgentShield API Client\n *\n * Lightweight client for calling the AgentShield enforce API from middleware.\n * Designed for Edge Runtime compatibility (no Node.js-specific APIs).\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * API client configuration\n */\nexport interface AgentShieldClientConfig {\n /** API key for authentication */\n apiKey: string;\n /** API base URL (defaults to production) */\n baseUrl?: string;\n /**\n * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.\n * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)\n * that the pixel cannot detect since they don't execute JavaScript.\n * @default true\n */\n useEdge?: boolean;\n /** Request timeout in milliseconds (default: 5000) */\n timeout?: number;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Enforcement action\n */\nexport type EnforcementAction = 'allow' | 'block' | 'redirect' | 'challenge' | 'log';\n\n/**\n * Enforcement decision from the API\n */\nexport interface EnforcementDecision {\n action: EnforcementAction;\n reason: string;\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n redirectUrl?: string;\n message?: string;\n metadata?: {\n policyVersion?: string;\n signatureVerified?: boolean;\n denyListMatch?: {\n clientDid?: string;\n agentDid?: string;\n clientName?: string;\n reason?: string;\n };\n };\n}\n\n/**\n * Detection result (optional in response)\n */\nexport interface DetectionResult {\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n verificationMethod?: string;\n reasons?: string[];\n /** Detection engine used: 'wasm' or 'javascript-fallback' */\n detectionMethod?: string;\n}\n\n/**\n * Enforce API response\n */\nexport interface EnforceResponse {\n success: boolean;\n data?: {\n decision: EnforcementDecision;\n processingTimeMs: number;\n requestId: string;\n detection?: DetectionResult;\n };\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Request input for enforce API\n */\nexport interface EnforceInput {\n /** HTTP headers from the incoming request */\n headers?: Record<string, string>;\n /** User-Agent header */\n userAgent?: string;\n /** Client IP address */\n ipAddress?: string;\n /** Request path */\n path?: string;\n /** Request URL */\n url?: string;\n /** HTTP method */\n method?: string;\n /** Request ID for tracing */\n requestId?: string;\n /** Options */\n options?: {\n /** Include full detection result */\n includeDetectionResult?: boolean;\n /** Cache TTL override */\n cacheTTL?: number;\n };\n}\n\n// ============================================================================\n// Client Implementation\n// ============================================================================\n\nconst DEFAULT_BASE_URL = 'https://kya.vouched.id';\nconst EDGE_DETECT_URL = 'https://detect.kya-os.ai';\nconst DEFAULT_TIMEOUT = 5000;\n\n/**\n * AgentShield API Client\n *\n * @example\n * ```typescript\n * const client = new AgentShieldClient({\n * apiKey: process.env.AGENTSHIELD_API_KEY!,\n * });\n *\n * const result = await client.enforce({\n * headers: Object.fromEntries(request.headers),\n * path: request.nextUrl.pathname,\n * method: request.method,\n * });\n *\n * if (result.decision.action === 'block') {\n * return new Response('Access denied', { status: 403 });\n * }\n * ```\n */\nexport class AgentShieldClient {\n private apiKey: string;\n private baseUrl: string;\n private useEdge: boolean;\n private timeout: number;\n private debug: boolean;\n\n constructor(config: AgentShieldClientConfig) {\n if (!config.apiKey) {\n throw new Error('AgentShield API key is required');\n }\n\n this.apiKey = config.apiKey;\n // Default to edge detection for better coverage (detects non-JS clients)\n this.useEdge = config.useEdge !== false; // true by default\n this.baseUrl = config.baseUrl || (this.useEdge ? EDGE_DETECT_URL : DEFAULT_BASE_URL);\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n }\n\n /**\n * Call the enforce API to check if a request should be allowed\n */\n async enforce(input: EnforceInput): Promise<EnforceResponse> {\n const startTime = Date.now();\n\n try {\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n // Use edge endpoint or Vercel API based on configuration\n const endpoint = this.useEdge\n ? `${this.baseUrl}/__detect/enforce`\n : `${this.baseUrl}/api/v1/enforce`;\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Request-ID': input.requestId || crypto.randomUUID(),\n },\n body: JSON.stringify(input),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = (await response.json()) as EnforceResponse;\n\n if (this.debug) {\n console.log('[AgentShield] Enforce response:', {\n status: response.status,\n action: data.data?.decision.action,\n processingTimeMs: Date.now() - startTime,\n });\n }\n\n // Handle non-2xx responses\n if (!response.ok) {\n return {\n success: false,\n error: {\n code: `HTTP_${response.status}`,\n message: data.error?.message || `HTTP error: ${response.status}`,\n },\n };\n }\n\n return data;\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Handle timeout\n if (error instanceof Error && error.name === 'AbortError') {\n if (this.debug) {\n console.warn('[AgentShield] Request timed out');\n }\n return {\n success: false,\n error: {\n code: 'TIMEOUT',\n message: `Request timed out after ${this.timeout}ms`,\n },\n };\n }\n\n // Handle network errors\n if (this.debug) {\n console.error('[AgentShield] Request failed:', error);\n }\n\n return {\n success: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Network request failed',\n },\n };\n }\n }\n\n /**\n * Quick check - returns just the action without full response parsing\n * Useful for very fast middleware that just needs allow/block\n */\n async quickCheck(input: EnforceInput): Promise<{\n action: EnforcementAction;\n error?: string;\n }> {\n const result = await this.enforce(input);\n\n if (!result.success || !result.data) {\n // On error, default to allow (fail-open)\n return {\n action: 'allow',\n error: result.error?.message,\n };\n }\n\n return {\n action: result.data.decision.action,\n };\n }\n}\n\n/**\n * Create a singleton client instance\n *\n * @example\n * ```typescript\n * // In middleware.ts\n * import { getAgentShieldClient } from '@kya-os/agentshield-nextjs';\n *\n * const client = getAgentShieldClient();\n * ```\n */\nlet clientInstance: AgentShieldClient | null = null;\n\nexport function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>): AgentShieldClient {\n if (!clientInstance) {\n const apiKey = config?.apiKey || process.env.AGENTSHIELD_API_KEY;\n\n if (!apiKey) {\n throw new Error(\n 'AgentShield API key is required. Set AGENTSHIELD_API_KEY environment variable or pass apiKey in config.'\n );\n }\n\n clientInstance = new AgentShieldClient({\n apiKey,\n baseUrl: config?.baseUrl || process.env.AGENTSHIELD_API_URL,\n // Default to edge detection unless explicitly disabled\n useEdge: config?.useEdge ?? process.env.AGENTSHIELD_USE_EDGE !== 'false',\n timeout: config?.timeout,\n debug: config?.debug || process.env.AGENTSHIELD_DEBUG === 'true',\n });\n }\n\n return clientInstance;\n}\n\n/**\n * Reset the singleton client (useful for testing)\n */\nexport function resetAgentShieldClient(): void {\n clientInstance = null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/api-client.ts"],"names":[],"mappings":"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","file":"api-client.js","sourcesContent":["/**\n * AgentShield API Client\n *\n * Lightweight client for calling the AgentShield enforce API from middleware.\n * Designed for Edge Runtime compatibility (no Node.js-specific APIs).\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * API client configuration\n */\nexport interface AgentShieldClientConfig {\n /** API key for authentication */\n apiKey: string;\n /** API base URL (defaults to production) */\n baseUrl?: string;\n /**\n * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.\n * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)\n * that the pixel cannot detect since they don't execute JavaScript.\n * @default true\n */\n useEdge?: boolean;\n /** Request timeout in milliseconds (default: 5000) */\n timeout?: number;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Enforcement action\n */\nexport type EnforcementAction = 'allow' | 'block' | 'redirect' | 'challenge' | 'log';\n\n/**\n * Enforcement decision from the API\n */\nexport interface EnforcementDecision {\n action: EnforcementAction;\n reason: string;\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n redirectUrl?: string;\n message?: string;\n metadata?: {\n policyVersion?: string;\n signatureVerified?: boolean;\n denyListMatch?: {\n clientDid?: string;\n agentDid?: string;\n clientName?: string;\n reason?: string;\n };\n };\n}\n\n/**\n * Detection result (optional in response)\n */\nexport interface DetectionResult {\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n /** Detection class: 'human', 'ai_agent', 'bot', 'incomplete_data' */\n detectionClass?: string;\n verificationMethod?: string;\n reasons?: string[];\n /** Detection engine used: 'wasm' or 'javascript-fallback' */\n detectionMethod?: string;\n}\n\n/**\n * Enforce API response\n */\nexport interface EnforceResponse {\n success: boolean;\n data?: {\n decision: EnforcementDecision;\n processingTimeMs: number;\n requestId: string;\n detection?: DetectionResult;\n };\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Request input for enforce API\n */\nexport interface EnforceInput {\n /** HTTP headers from the incoming request */\n headers?: Record<string, string>;\n /** User-Agent header */\n userAgent?: string;\n /** Client IP address */\n ipAddress?: string;\n /** Request path */\n path?: string;\n /** Request URL */\n url?: string;\n /** HTTP method */\n method?: string;\n /** Request ID for tracing */\n requestId?: string;\n /** Options */\n options?: {\n /** Include full detection result */\n includeDetectionResult?: boolean;\n /** Cache TTL override */\n cacheTTL?: number;\n };\n}\n\n/**\n * Input for logging a detection result\n */\nexport interface LogDetectionInput {\n /** Detection result from Gateway */\n detection: DetectionResult;\n /** Request context */\n context: {\n userAgent?: string;\n ipAddress?: string;\n path?: string;\n url?: string;\n method?: string;\n };\n /** Source of the detection */\n source?: 'gateway' | 'middleware';\n}\n\n// ============================================================================\n// Client Implementation\n// ============================================================================\n\nconst DEFAULT_BASE_URL = 'https://kya.vouched.id';\nconst EDGE_DETECT_URL = 'https://detect.kya-os.ai';\nconst DEFAULT_TIMEOUT = 5000;\n\n/**\n * AgentShield API Client\n *\n * @example\n * ```typescript\n * const client = new AgentShieldClient({\n * apiKey: process.env.AGENTSHIELD_API_KEY!,\n * });\n *\n * const result = await client.enforce({\n * headers: Object.fromEntries(request.headers),\n * path: request.nextUrl.pathname,\n * method: request.method,\n * });\n *\n * if (result.decision.action === 'block') {\n * return new Response('Access denied', { status: 403 });\n * }\n * ```\n */\nexport class AgentShieldClient {\n private apiKey: string;\n private baseUrl: string;\n private useEdge: boolean;\n private timeout: number;\n private debug: boolean;\n\n constructor(config: AgentShieldClientConfig) {\n if (!config.apiKey) {\n throw new Error('AgentShield API key is required');\n }\n\n this.apiKey = config.apiKey;\n // Default to edge detection for better coverage (detects non-JS clients)\n this.useEdge = config.useEdge !== false; // true by default\n this.baseUrl = config.baseUrl || (this.useEdge ? EDGE_DETECT_URL : DEFAULT_BASE_URL);\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n }\n\n /**\n * Call the enforce API to check if a request should be allowed\n */\n async enforce(input: EnforceInput): Promise<EnforceResponse> {\n const startTime = Date.now();\n\n try {\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n // Use edge endpoint or Vercel API based on configuration\n const endpoint = this.useEdge\n ? `${this.baseUrl}/__detect/enforce`\n : `${this.baseUrl}/api/v1/enforce`;\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Request-ID': input.requestId || crypto.randomUUID(),\n },\n body: JSON.stringify(input),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = (await response.json()) as EnforceResponse;\n\n if (this.debug) {\n console.log('[AgentShield] Enforce response:', {\n status: response.status,\n action: data.data?.decision.action,\n processingTimeMs: Date.now() - startTime,\n });\n }\n\n // Handle non-2xx responses\n if (!response.ok) {\n return {\n success: false,\n error: {\n code: `HTTP_${response.status}`,\n message: data.error?.message || `HTTP error: ${response.status}`,\n },\n };\n }\n\n return data;\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Handle timeout\n if (error instanceof Error && error.name === 'AbortError') {\n if (this.debug) {\n console.warn('[AgentShield] Request timed out');\n }\n return {\n success: false,\n error: {\n code: 'TIMEOUT',\n message: `Request timed out after ${this.timeout}ms`,\n },\n };\n }\n\n // Handle network errors\n if (this.debug) {\n console.error('[AgentShield] Request failed:', error);\n }\n\n return {\n success: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Network request failed',\n },\n };\n }\n }\n\n /**\n * Quick check - returns just the action without full response parsing\n * Useful for very fast middleware that just needs allow/block\n */\n async quickCheck(input: EnforceInput): Promise<{\n action: EnforcementAction;\n error?: string;\n }> {\n const result = await this.enforce(input);\n\n if (!result.success || !result.data) {\n // On error, default to allow (fail-open)\n return {\n action: 'allow',\n error: result.error?.message,\n };\n }\n\n return {\n action: result.data.decision.action,\n };\n }\n\n /**\n * Check if this client is using edge detection (Gateway Worker)\n */\n isUsingEdge(): boolean {\n return this.useEdge;\n }\n\n /**\n * Log a detection result to AgentShield database.\n * Use after Gateway Worker detection to persist results.\n * Fire-and-forget - returns immediately without waiting for DB write.\n *\n * @example\n * ```typescript\n * // After receiving Gateway response\n * if (client.isUsingEdge() && response.data?.detection) {\n * client.logDetection({\n * detection: response.data.detection,\n * context: { userAgent, ipAddress, path, url, method }\n * }).catch(err => console.error('Log failed:', err));\n * }\n * ```\n */\n async logDetection(input: LogDetectionInput): Promise<void> {\n // Don't await - fire and forget\n // Use the base URL (not edge) for logging since this goes to the main API\n const logEndpoint = this.useEdge\n ? `${DEFAULT_BASE_URL}/api/v1/log-detection`\n : `${this.baseUrl}/api/v1/log-detection`;\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(logEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n detection: {\n isAgent: input.detection.isAgent,\n confidence: input.detection.confidence,\n agentName: input.detection.agentName,\n agentType: input.detection.agentType,\n detectionClass: input.detection.detectionClass,\n verificationMethod: input.detection.verificationMethod,\n reasons: input.detection.reasons,\n },\n context: input.context,\n source: input.source || 'gateway',\n }),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok && this.debug) {\n console.warn('[AgentShield] Log detection returned non-2xx:', response.status);\n }\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Silently fail for fire-and-forget, but log in debug mode\n if (this.debug) {\n console.error('[AgentShield] Log detection failed:', error);\n }\n // Re-throw so caller can catch if needed\n throw error;\n }\n }\n}\n\n/**\n * Create a singleton client instance\n *\n * @example\n * ```typescript\n * // In middleware.ts\n * import { getAgentShieldClient } from '@kya-os/agentshield-nextjs';\n *\n * const client = getAgentShieldClient();\n * ```\n */\nlet clientInstance: AgentShieldClient | null = null;\n\nexport function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>): AgentShieldClient {\n if (!clientInstance) {\n const apiKey = config?.apiKey || process.env.AGENTSHIELD_API_KEY;\n\n if (!apiKey) {\n throw new Error(\n 'AgentShield API key is required. Set AGENTSHIELD_API_KEY environment variable or pass apiKey in config.'\n );\n }\n\n clientInstance = new AgentShieldClient({\n apiKey,\n baseUrl: config?.baseUrl || process.env.AGENTSHIELD_API_URL,\n // Default to edge detection unless explicitly disabled\n useEdge: config?.useEdge ?? process.env.AGENTSHIELD_USE_EDGE !== 'false',\n timeout: config?.timeout,\n debug: config?.debug || process.env.AGENTSHIELD_DEBUG === 'true',\n });\n }\n\n return clientInstance;\n}\n\n/**\n * Reset the singleton client (useful for testing)\n */\nexport function resetAgentShieldClient(): void {\n clientInstance = null;\n}\n"]}
|
package/dist/api-client.mjs
CHANGED
|
@@ -102,6 +102,70 @@ var AgentShieldClient = class {
|
|
|
102
102
|
action: result.data.decision.action
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Check if this client is using edge detection (Gateway Worker)
|
|
107
|
+
*/
|
|
108
|
+
isUsingEdge() {
|
|
109
|
+
return this.useEdge;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Log a detection result to AgentShield database.
|
|
113
|
+
* Use after Gateway Worker detection to persist results.
|
|
114
|
+
* Fire-and-forget - returns immediately without waiting for DB write.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* // After receiving Gateway response
|
|
119
|
+
* if (client.isUsingEdge() && response.data?.detection) {
|
|
120
|
+
* client.logDetection({
|
|
121
|
+
* detection: response.data.detection,
|
|
122
|
+
* context: { userAgent, ipAddress, path, url, method }
|
|
123
|
+
* }).catch(err => console.error('Log failed:', err));
|
|
124
|
+
* }
|
|
125
|
+
* ```
|
|
126
|
+
*/
|
|
127
|
+
async logDetection(input) {
|
|
128
|
+
const logEndpoint = this.useEdge ? `${DEFAULT_BASE_URL}/api/v1/log-detection` : `${this.baseUrl}/api/v1/log-detection`;
|
|
129
|
+
try {
|
|
130
|
+
const controller = new AbortController();
|
|
131
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
132
|
+
try {
|
|
133
|
+
const response = await fetch(logEndpoint, {
|
|
134
|
+
method: "POST",
|
|
135
|
+
headers: {
|
|
136
|
+
"Content-Type": "application/json",
|
|
137
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
138
|
+
},
|
|
139
|
+
body: JSON.stringify({
|
|
140
|
+
detection: {
|
|
141
|
+
isAgent: input.detection.isAgent,
|
|
142
|
+
confidence: input.detection.confidence,
|
|
143
|
+
agentName: input.detection.agentName,
|
|
144
|
+
agentType: input.detection.agentType,
|
|
145
|
+
detectionClass: input.detection.detectionClass,
|
|
146
|
+
verificationMethod: input.detection.verificationMethod,
|
|
147
|
+
reasons: input.detection.reasons
|
|
148
|
+
},
|
|
149
|
+
context: input.context,
|
|
150
|
+
source: input.source || "gateway"
|
|
151
|
+
}),
|
|
152
|
+
signal: controller.signal
|
|
153
|
+
});
|
|
154
|
+
clearTimeout(timeoutId);
|
|
155
|
+
if (!response.ok && this.debug) {
|
|
156
|
+
console.warn("[AgentShield] Log detection returned non-2xx:", response.status);
|
|
157
|
+
}
|
|
158
|
+
} catch (error) {
|
|
159
|
+
clearTimeout(timeoutId);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
} catch (error) {
|
|
163
|
+
if (this.debug) {
|
|
164
|
+
console.error("[AgentShield] Log detection failed:", error);
|
|
165
|
+
}
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
105
169
|
};
|
|
106
170
|
var clientInstance = null;
|
|
107
171
|
function getAgentShieldClient(config) {
|
package/dist/api-client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api-client.ts"],"names":[],"mappings":"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","file":"api-client.mjs","sourcesContent":["/**\n * AgentShield API Client\n *\n * Lightweight client for calling the AgentShield enforce API from middleware.\n * Designed for Edge Runtime compatibility (no Node.js-specific APIs).\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * API client configuration\n */\nexport interface AgentShieldClientConfig {\n /** API key for authentication */\n apiKey: string;\n /** API base URL (defaults to production) */\n baseUrl?: string;\n /**\n * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.\n * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)\n * that the pixel cannot detect since they don't execute JavaScript.\n * @default true\n */\n useEdge?: boolean;\n /** Request timeout in milliseconds (default: 5000) */\n timeout?: number;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Enforcement action\n */\nexport type EnforcementAction = 'allow' | 'block' | 'redirect' | 'challenge' | 'log';\n\n/**\n * Enforcement decision from the API\n */\nexport interface EnforcementDecision {\n action: EnforcementAction;\n reason: string;\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n redirectUrl?: string;\n message?: string;\n metadata?: {\n policyVersion?: string;\n signatureVerified?: boolean;\n denyListMatch?: {\n clientDid?: string;\n agentDid?: string;\n clientName?: string;\n reason?: string;\n };\n };\n}\n\n/**\n * Detection result (optional in response)\n */\nexport interface DetectionResult {\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n verificationMethod?: string;\n reasons?: string[];\n /** Detection engine used: 'wasm' or 'javascript-fallback' */\n detectionMethod?: string;\n}\n\n/**\n * Enforce API response\n */\nexport interface EnforceResponse {\n success: boolean;\n data?: {\n decision: EnforcementDecision;\n processingTimeMs: number;\n requestId: string;\n detection?: DetectionResult;\n };\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Request input for enforce API\n */\nexport interface EnforceInput {\n /** HTTP headers from the incoming request */\n headers?: Record<string, string>;\n /** User-Agent header */\n userAgent?: string;\n /** Client IP address */\n ipAddress?: string;\n /** Request path */\n path?: string;\n /** Request URL */\n url?: string;\n /** HTTP method */\n method?: string;\n /** Request ID for tracing */\n requestId?: string;\n /** Options */\n options?: {\n /** Include full detection result */\n includeDetectionResult?: boolean;\n /** Cache TTL override */\n cacheTTL?: number;\n };\n}\n\n// ============================================================================\n// Client Implementation\n// ============================================================================\n\nconst DEFAULT_BASE_URL = 'https://kya.vouched.id';\nconst EDGE_DETECT_URL = 'https://detect.kya-os.ai';\nconst DEFAULT_TIMEOUT = 5000;\n\n/**\n * AgentShield API Client\n *\n * @example\n * ```typescript\n * const client = new AgentShieldClient({\n * apiKey: process.env.AGENTSHIELD_API_KEY!,\n * });\n *\n * const result = await client.enforce({\n * headers: Object.fromEntries(request.headers),\n * path: request.nextUrl.pathname,\n * method: request.method,\n * });\n *\n * if (result.decision.action === 'block') {\n * return new Response('Access denied', { status: 403 });\n * }\n * ```\n */\nexport class AgentShieldClient {\n private apiKey: string;\n private baseUrl: string;\n private useEdge: boolean;\n private timeout: number;\n private debug: boolean;\n\n constructor(config: AgentShieldClientConfig) {\n if (!config.apiKey) {\n throw new Error('AgentShield API key is required');\n }\n\n this.apiKey = config.apiKey;\n // Default to edge detection for better coverage (detects non-JS clients)\n this.useEdge = config.useEdge !== false; // true by default\n this.baseUrl = config.baseUrl || (this.useEdge ? EDGE_DETECT_URL : DEFAULT_BASE_URL);\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n }\n\n /**\n * Call the enforce API to check if a request should be allowed\n */\n async enforce(input: EnforceInput): Promise<EnforceResponse> {\n const startTime = Date.now();\n\n try {\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n // Use edge endpoint or Vercel API based on configuration\n const endpoint = this.useEdge\n ? `${this.baseUrl}/__detect/enforce`\n : `${this.baseUrl}/api/v1/enforce`;\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Request-ID': input.requestId || crypto.randomUUID(),\n },\n body: JSON.stringify(input),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = (await response.json()) as EnforceResponse;\n\n if (this.debug) {\n console.log('[AgentShield] Enforce response:', {\n status: response.status,\n action: data.data?.decision.action,\n processingTimeMs: Date.now() - startTime,\n });\n }\n\n // Handle non-2xx responses\n if (!response.ok) {\n return {\n success: false,\n error: {\n code: `HTTP_${response.status}`,\n message: data.error?.message || `HTTP error: ${response.status}`,\n },\n };\n }\n\n return data;\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Handle timeout\n if (error instanceof Error && error.name === 'AbortError') {\n if (this.debug) {\n console.warn('[AgentShield] Request timed out');\n }\n return {\n success: false,\n error: {\n code: 'TIMEOUT',\n message: `Request timed out after ${this.timeout}ms`,\n },\n };\n }\n\n // Handle network errors\n if (this.debug) {\n console.error('[AgentShield] Request failed:', error);\n }\n\n return {\n success: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Network request failed',\n },\n };\n }\n }\n\n /**\n * Quick check - returns just the action without full response parsing\n * Useful for very fast middleware that just needs allow/block\n */\n async quickCheck(input: EnforceInput): Promise<{\n action: EnforcementAction;\n error?: string;\n }> {\n const result = await this.enforce(input);\n\n if (!result.success || !result.data) {\n // On error, default to allow (fail-open)\n return {\n action: 'allow',\n error: result.error?.message,\n };\n }\n\n return {\n action: result.data.decision.action,\n };\n }\n}\n\n/**\n * Create a singleton client instance\n *\n * @example\n * ```typescript\n * // In middleware.ts\n * import { getAgentShieldClient } from '@kya-os/agentshield-nextjs';\n *\n * const client = getAgentShieldClient();\n * ```\n */\nlet clientInstance: AgentShieldClient | null = null;\n\nexport function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>): AgentShieldClient {\n if (!clientInstance) {\n const apiKey = config?.apiKey || process.env.AGENTSHIELD_API_KEY;\n\n if (!apiKey) {\n throw new Error(\n 'AgentShield API key is required. Set AGENTSHIELD_API_KEY environment variable or pass apiKey in config.'\n );\n }\n\n clientInstance = new AgentShieldClient({\n apiKey,\n baseUrl: config?.baseUrl || process.env.AGENTSHIELD_API_URL,\n // Default to edge detection unless explicitly disabled\n useEdge: config?.useEdge ?? process.env.AGENTSHIELD_USE_EDGE !== 'false',\n timeout: config?.timeout,\n debug: config?.debug || process.env.AGENTSHIELD_DEBUG === 'true',\n });\n }\n\n return clientInstance;\n}\n\n/**\n * Reset the singleton client (useful for testing)\n */\nexport function resetAgentShieldClient(): void {\n clientInstance = null;\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/api-client.ts"],"names":[],"mappings":";AA+IA,IAAM,gBAAA,GAAmB,wBAAA;AACzB,IAAM,eAAA,GAAkB,0BAAA;AACxB,IAAM,eAAA,GAAkB,GAAA;AAsBjB,IAAM,oBAAN,MAAwB;AAAA,EACrB,MAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EAER,YAAY,MAAA,EAAiC;AAC3C,IAAA,IAAI,CAAC,OAAO,MAAA,EAAQ;AAClB,MAAA,MAAM,IAAI,MAAM,iCAAiC,CAAA;AAAA,IACnD;AAEA,IAAA,IAAA,CAAK,SAAS,MAAA,CAAO,MAAA;AAErB,IAAA,IAAA,CAAK,OAAA,GAAU,OAAO,OAAA,KAAY,KAAA;AAClC,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA,CAAO,OAAA,KAAY,IAAA,CAAK,UAAU,eAAA,GAAkB,gBAAA,CAAA;AACnE,IAAA,IAAA,CAAK,OAAA,GAAU,OAAO,OAAA,IAAW,eAAA;AACjC,IAAA,IAAA,CAAK,KAAA,GAAQ,OAAO,KAAA,IAAS,KAAA;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAQ,KAAA,EAA+C;AAC3D,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,IAAA,IAAI;AAEF,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,MAAM,YAAY,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,OAAO,CAAA;AAEnE,MAAA,IAAI;AAEF,QAAA,MAAM,QAAA,GAAW,KAAK,OAAA,GAClB,CAAA,EAAG,KAAK,OAAO,CAAA,iBAAA,CAAA,GACf,CAAA,EAAG,IAAA,CAAK,OAAO,CAAA,eAAA,CAAA;AAEnB,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,QAAA,EAAU;AAAA,UACrC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,YACpC,cAAA,EAAgB,KAAA,CAAM,SAAA,IAAa,MAAA,CAAO,UAAA;AAAW,WACvD;AAAA,UACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAA;AAAA,UAC1B,QAAQ,UAAA,CAAW;AAAA,SACpB,CAAA;AAED,QAAA,YAAA,CAAa,SAAS,CAAA;AAGtB,QAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAElC,QAAA,IAAI,KAAK,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,IAAI,iCAAA,EAAmC;AAAA,YAC7C,QAAQ,QAAA,CAAS,MAAA;AAAA,YACjB,MAAA,EAAQ,IAAA,CAAK,IAAA,EAAM,QAAA,CAAS,MAAA;AAAA,YAC5B,gBAAA,EAAkB,IAAA,CAAK,GAAA,EAAI,GAAI;AAAA,WAChC,CAAA;AAAA,QACH;AAGA,QAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AAChB,UAAA,OAAO;AAAA,YACL,OAAA,EAAS,KAAA;AAAA,YACT,KAAA,EAAO;AAAA,cACL,IAAA,EAAM,CAAA,KAAA,EAAQ,QAAA,CAAS,MAAM,CAAA,CAAA;AAAA,cAC7B,SAAS,IAAA,CAAK,KAAA,EAAO,OAAA,IAAW,CAAA,YAAA,EAAe,SAAS,MAAM,CAAA;AAAA;AAChE,WACF;AAAA,QACF;AAEA,QAAA,OAAO,IAAA;AAAA,MACT,SAAS,KAAA,EAAO;AACd,QAAA,YAAA,CAAa,SAAS,CAAA;AACtB,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,KAAA,YAAiB,KAAA,IAAS,KAAA,CAAM,IAAA,KAAS,YAAA,EAAc;AACzD,QAAA,IAAI,KAAK,KAAA,EAAO;AACd,UAAA,OAAA,CAAQ,KAAK,iCAAiC,CAAA;AAAA,QAChD;AACA,QAAA,OAAO;AAAA,UACL,OAAA,EAAS,KAAA;AAAA,UACT,KAAA,EAAO;AAAA,YACL,IAAA,EAAM,SAAA;AAAA,YACN,OAAA,EAAS,CAAA,wBAAA,EAA2B,IAAA,CAAK,OAAO,CAAA,EAAA;AAAA;AAClD,SACF;AAAA,MACF;AAGA,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,iCAAiC,KAAK,CAAA;AAAA,MACtD;AAEA,MAAA,OAAO;AAAA,QACL,OAAA,EAAS,KAAA;AAAA,QACT,KAAA,EAAO;AAAA,UACL,IAAA,EAAM,eAAA;AAAA,UACN,OAAA,EAAS,KAAA,YAAiB,KAAA,GAAQ,KAAA,CAAM,OAAA,GAAU;AAAA;AACpD,OACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,KAAA,EAGd;AACD,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,OAAA,CAAQ,KAAK,CAAA;AAEvC,IAAA,IAAI,CAAC,MAAA,CAAO,OAAA,IAAW,CAAC,OAAO,IAAA,EAAM;AAEnC,MAAA,OAAO;AAAA,QACL,MAAA,EAAQ,OAAA;AAAA,QACR,KAAA,EAAO,OAAO,KAAA,EAAO;AAAA,OACvB;AAAA,IACF;AAEA,IAAA,OAAO;AAAA,MACL,MAAA,EAAQ,MAAA,CAAO,IAAA,CAAK,QAAA,CAAS;AAAA,KAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAA,GAAuB;AACrB,IAAA,OAAO,IAAA,CAAK,OAAA;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAkBA,MAAM,aAAa,KAAA,EAAyC;AAG1D,IAAA,MAAM,WAAA,GAAc,KAAK,OAAA,GACrB,CAAA,EAAG,gBAAgB,CAAA,qBAAA,CAAA,GACnB,CAAA,EAAG,KAAK,OAAO,CAAA,qBAAA,CAAA;AAEnB,IAAA,IAAI;AACF,MAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,MAAA,MAAM,YAAY,UAAA,CAAW,MAAM,WAAW,KAAA,EAAM,EAAG,KAAK,OAAO,CAAA;AAEnE,MAAA,IAAI;AACF,QAAA,MAAM,QAAA,GAAW,MAAM,KAAA,CAAM,WAAA,EAAa;AAAA,UACxC,MAAA,EAAQ,MAAA;AAAA,UACR,OAAA,EAAS;AAAA,YACP,cAAA,EAAgB,kBAAA;AAAA,YAChB,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,CAAA;AAAA,WACtC;AAAA,UACA,IAAA,EAAM,KAAK,SAAA,CAAU;AAAA,YACnB,SAAA,EAAW;AAAA,cACT,OAAA,EAAS,MAAM,SAAA,CAAU,OAAA;AAAA,cACzB,UAAA,EAAY,MAAM,SAAA,CAAU,UAAA;AAAA,cAC5B,SAAA,EAAW,MAAM,SAAA,CAAU,SAAA;AAAA,cAC3B,SAAA,EAAW,MAAM,SAAA,CAAU,SAAA;AAAA,cAC3B,cAAA,EAAgB,MAAM,SAAA,CAAU,cAAA;AAAA,cAChC,kBAAA,EAAoB,MAAM,SAAA,CAAU,kBAAA;AAAA,cACpC,OAAA,EAAS,MAAM,SAAA,CAAU;AAAA,aAC3B;AAAA,YACA,SAAS,KAAA,CAAM,OAAA;AAAA,YACf,MAAA,EAAQ,MAAM,MAAA,IAAU;AAAA,WACzB,CAAA;AAAA,UACD,QAAQ,UAAA,CAAW;AAAA,SACpB,CAAA;AAED,QAAA,YAAA,CAAa,SAAS,CAAA;AAEtB,QAAA,IAAI,CAAC,QAAA,CAAS,EAAA,IAAM,IAAA,CAAK,KAAA,EAAO;AAC9B,UAAA,OAAA,CAAQ,IAAA,CAAK,+CAAA,EAAiD,QAAA,CAAS,MAAM,CAAA;AAAA,QAC/E;AAAA,MACF,SAAS,KAAA,EAAO;AACd,QAAA,YAAA,CAAa,SAAS,CAAA;AACtB,QAAA,MAAM,KAAA;AAAA,MACR;AAAA,IACF,SAAS,KAAA,EAAO;AAEd,MAAA,IAAI,KAAK,KAAA,EAAO;AACd,QAAA,OAAA,CAAQ,KAAA,CAAM,uCAAuC,KAAK,CAAA;AAAA,MAC5D;AAEA,MAAA,MAAM,KAAA;AAAA,IACR;AAAA,EACF;AACF;AAaA,IAAI,cAAA,GAA2C,IAAA;AAExC,SAAS,qBAAqB,MAAA,EAA8D;AACjG,EAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,IAAA,MAAM,MAAA,GAAS,MAAA,EAAQ,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,mBAAA;AAE7C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,KAAA;AAAA,QACR;AAAA,OACF;AAAA,IACF;AAEA,IAAA,cAAA,GAAiB,IAAI,iBAAA,CAAkB;AAAA,MACrC,MAAA;AAAA,MACA,OAAA,EAAS,MAAA,EAAQ,OAAA,IAAW,OAAA,CAAQ,GAAA,CAAI,mBAAA;AAAA;AAAA,MAExC,OAAA,EAAS,MAAA,EAAQ,OAAA,IAAW,OAAA,CAAQ,IAAI,oBAAA,KAAyB,OAAA;AAAA,MACjE,SAAS,MAAA,EAAQ,OAAA;AAAA,MACjB,KAAA,EAAO,MAAA,EAAQ,KAAA,IAAS,OAAA,CAAQ,IAAI,iBAAA,KAAsB;AAAA,KAC3D,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,cAAA;AACT;AAKO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,cAAA,GAAiB,IAAA;AACnB","file":"api-client.mjs","sourcesContent":["/**\n * AgentShield API Client\n *\n * Lightweight client for calling the AgentShield enforce API from middleware.\n * Designed for Edge Runtime compatibility (no Node.js-specific APIs).\n */\n\n// ============================================================================\n// Types\n// ============================================================================\n\n/**\n * API client configuration\n */\nexport interface AgentShieldClientConfig {\n /** API key for authentication */\n apiKey: string;\n /** API base URL (defaults to production) */\n baseUrl?: string;\n /**\n * Use edge detection for lower latency (~30-50ms vs ~150ms) and better coverage.\n * Edge detection can identify non-JS clients (curl, Python, Claude Code WebFetch)\n * that the pixel cannot detect since they don't execute JavaScript.\n * @default true\n */\n useEdge?: boolean;\n /** Request timeout in milliseconds (default: 5000) */\n timeout?: number;\n /** Enable debug logging */\n debug?: boolean;\n}\n\n/**\n * Enforcement action\n */\nexport type EnforcementAction = 'allow' | 'block' | 'redirect' | 'challenge' | 'log';\n\n/**\n * Enforcement decision from the API\n */\nexport interface EnforcementDecision {\n action: EnforcementAction;\n reason: string;\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n redirectUrl?: string;\n message?: string;\n metadata?: {\n policyVersion?: string;\n signatureVerified?: boolean;\n denyListMatch?: {\n clientDid?: string;\n agentDid?: string;\n clientName?: string;\n reason?: string;\n };\n };\n}\n\n/**\n * Detection result (optional in response)\n */\nexport interface DetectionResult {\n isAgent: boolean;\n confidence: number;\n agentName?: string;\n agentType?: string;\n /** Detection class: 'human', 'ai_agent', 'bot', 'incomplete_data' */\n detectionClass?: string;\n verificationMethod?: string;\n reasons?: string[];\n /** Detection engine used: 'wasm' or 'javascript-fallback' */\n detectionMethod?: string;\n}\n\n/**\n * Enforce API response\n */\nexport interface EnforceResponse {\n success: boolean;\n data?: {\n decision: EnforcementDecision;\n processingTimeMs: number;\n requestId: string;\n detection?: DetectionResult;\n };\n error?: {\n code: string;\n message: string;\n };\n}\n\n/**\n * Request input for enforce API\n */\nexport interface EnforceInput {\n /** HTTP headers from the incoming request */\n headers?: Record<string, string>;\n /** User-Agent header */\n userAgent?: string;\n /** Client IP address */\n ipAddress?: string;\n /** Request path */\n path?: string;\n /** Request URL */\n url?: string;\n /** HTTP method */\n method?: string;\n /** Request ID for tracing */\n requestId?: string;\n /** Options */\n options?: {\n /** Include full detection result */\n includeDetectionResult?: boolean;\n /** Cache TTL override */\n cacheTTL?: number;\n };\n}\n\n/**\n * Input for logging a detection result\n */\nexport interface LogDetectionInput {\n /** Detection result from Gateway */\n detection: DetectionResult;\n /** Request context */\n context: {\n userAgent?: string;\n ipAddress?: string;\n path?: string;\n url?: string;\n method?: string;\n };\n /** Source of the detection */\n source?: 'gateway' | 'middleware';\n}\n\n// ============================================================================\n// Client Implementation\n// ============================================================================\n\nconst DEFAULT_BASE_URL = 'https://kya.vouched.id';\nconst EDGE_DETECT_URL = 'https://detect.kya-os.ai';\nconst DEFAULT_TIMEOUT = 5000;\n\n/**\n * AgentShield API Client\n *\n * @example\n * ```typescript\n * const client = new AgentShieldClient({\n * apiKey: process.env.AGENTSHIELD_API_KEY!,\n * });\n *\n * const result = await client.enforce({\n * headers: Object.fromEntries(request.headers),\n * path: request.nextUrl.pathname,\n * method: request.method,\n * });\n *\n * if (result.decision.action === 'block') {\n * return new Response('Access denied', { status: 403 });\n * }\n * ```\n */\nexport class AgentShieldClient {\n private apiKey: string;\n private baseUrl: string;\n private useEdge: boolean;\n private timeout: number;\n private debug: boolean;\n\n constructor(config: AgentShieldClientConfig) {\n if (!config.apiKey) {\n throw new Error('AgentShield API key is required');\n }\n\n this.apiKey = config.apiKey;\n // Default to edge detection for better coverage (detects non-JS clients)\n this.useEdge = config.useEdge !== false; // true by default\n this.baseUrl = config.baseUrl || (this.useEdge ? EDGE_DETECT_URL : DEFAULT_BASE_URL);\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.debug = config.debug || false;\n }\n\n /**\n * Call the enforce API to check if a request should be allowed\n */\n async enforce(input: EnforceInput): Promise<EnforceResponse> {\n const startTime = Date.now();\n\n try {\n // Create abort controller for timeout\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n // Use edge endpoint or Vercel API based on configuration\n const endpoint = this.useEdge\n ? `${this.baseUrl}/__detect/enforce`\n : `${this.baseUrl}/api/v1/enforce`;\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n 'X-Request-ID': input.requestId || crypto.randomUUID(),\n },\n body: JSON.stringify(input),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = (await response.json()) as EnforceResponse;\n\n if (this.debug) {\n console.log('[AgentShield] Enforce response:', {\n status: response.status,\n action: data.data?.decision.action,\n processingTimeMs: Date.now() - startTime,\n });\n }\n\n // Handle non-2xx responses\n if (!response.ok) {\n return {\n success: false,\n error: {\n code: `HTTP_${response.status}`,\n message: data.error?.message || `HTTP error: ${response.status}`,\n },\n };\n }\n\n return data;\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Handle timeout\n if (error instanceof Error && error.name === 'AbortError') {\n if (this.debug) {\n console.warn('[AgentShield] Request timed out');\n }\n return {\n success: false,\n error: {\n code: 'TIMEOUT',\n message: `Request timed out after ${this.timeout}ms`,\n },\n };\n }\n\n // Handle network errors\n if (this.debug) {\n console.error('[AgentShield] Request failed:', error);\n }\n\n return {\n success: false,\n error: {\n code: 'NETWORK_ERROR',\n message: error instanceof Error ? error.message : 'Network request failed',\n },\n };\n }\n }\n\n /**\n * Quick check - returns just the action without full response parsing\n * Useful for very fast middleware that just needs allow/block\n */\n async quickCheck(input: EnforceInput): Promise<{\n action: EnforcementAction;\n error?: string;\n }> {\n const result = await this.enforce(input);\n\n if (!result.success || !result.data) {\n // On error, default to allow (fail-open)\n return {\n action: 'allow',\n error: result.error?.message,\n };\n }\n\n return {\n action: result.data.decision.action,\n };\n }\n\n /**\n * Check if this client is using edge detection (Gateway Worker)\n */\n isUsingEdge(): boolean {\n return this.useEdge;\n }\n\n /**\n * Log a detection result to AgentShield database.\n * Use after Gateway Worker detection to persist results.\n * Fire-and-forget - returns immediately without waiting for DB write.\n *\n * @example\n * ```typescript\n * // After receiving Gateway response\n * if (client.isUsingEdge() && response.data?.detection) {\n * client.logDetection({\n * detection: response.data.detection,\n * context: { userAgent, ipAddress, path, url, method }\n * }).catch(err => console.error('Log failed:', err));\n * }\n * ```\n */\n async logDetection(input: LogDetectionInput): Promise<void> {\n // Don't await - fire and forget\n // Use the base URL (not edge) for logging since this goes to the main API\n const logEndpoint = this.useEdge\n ? `${DEFAULT_BASE_URL}/api/v1/log-detection`\n : `${this.baseUrl}/api/v1/log-detection`;\n\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(logEndpoint, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({\n detection: {\n isAgent: input.detection.isAgent,\n confidence: input.detection.confidence,\n agentName: input.detection.agentName,\n agentType: input.detection.agentType,\n detectionClass: input.detection.detectionClass,\n verificationMethod: input.detection.verificationMethod,\n reasons: input.detection.reasons,\n },\n context: input.context,\n source: input.source || 'gateway',\n }),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok && this.debug) {\n console.warn('[AgentShield] Log detection returned non-2xx:', response.status);\n }\n } catch (error) {\n clearTimeout(timeoutId);\n throw error;\n }\n } catch (error) {\n // Silently fail for fire-and-forget, but log in debug mode\n if (this.debug) {\n console.error('[AgentShield] Log detection failed:', error);\n }\n // Re-throw so caller can catch if needed\n throw error;\n }\n }\n}\n\n/**\n * Create a singleton client instance\n *\n * @example\n * ```typescript\n * // In middleware.ts\n * import { getAgentShieldClient } from '@kya-os/agentshield-nextjs';\n *\n * const client = getAgentShieldClient();\n * ```\n */\nlet clientInstance: AgentShieldClient | null = null;\n\nexport function getAgentShieldClient(config?: Partial<AgentShieldClientConfig>): AgentShieldClient {\n if (!clientInstance) {\n const apiKey = config?.apiKey || process.env.AGENTSHIELD_API_KEY;\n\n if (!apiKey) {\n throw new Error(\n 'AgentShield API key is required. Set AGENTSHIELD_API_KEY environment variable or pass apiKey in config.'\n );\n }\n\n clientInstance = new AgentShieldClient({\n apiKey,\n baseUrl: config?.baseUrl || process.env.AGENTSHIELD_API_URL,\n // Default to edge detection unless explicitly disabled\n useEdge: config?.useEdge ?? process.env.AGENTSHIELD_USE_EDGE !== 'false',\n timeout: config?.timeout,\n debug: config?.debug || process.env.AGENTSHIELD_DEBUG === 'true',\n });\n }\n\n return clientInstance;\n}\n\n/**\n * Reset the singleton client (useful for testing)\n */\nexport function resetAgentShieldClient(): void {\n clientInstance = null;\n}\n"]}
|
package/dist/api-middleware.js
CHANGED
|
@@ -108,6 +108,70 @@ var AgentShieldClient = class {
|
|
|
108
108
|
action: result.data.decision.action
|
|
109
109
|
};
|
|
110
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Check if this client is using edge detection (Gateway Worker)
|
|
113
|
+
*/
|
|
114
|
+
isUsingEdge() {
|
|
115
|
+
return this.useEdge;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Log a detection result to AgentShield database.
|
|
119
|
+
* Use after Gateway Worker detection to persist results.
|
|
120
|
+
* Fire-and-forget - returns immediately without waiting for DB write.
|
|
121
|
+
*
|
|
122
|
+
* @example
|
|
123
|
+
* ```typescript
|
|
124
|
+
* // After receiving Gateway response
|
|
125
|
+
* if (client.isUsingEdge() && response.data?.detection) {
|
|
126
|
+
* client.logDetection({
|
|
127
|
+
* detection: response.data.detection,
|
|
128
|
+
* context: { userAgent, ipAddress, path, url, method }
|
|
129
|
+
* }).catch(err => console.error('Log failed:', err));
|
|
130
|
+
* }
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
async logDetection(input) {
|
|
134
|
+
const logEndpoint = this.useEdge ? `${DEFAULT_BASE_URL}/api/v1/log-detection` : `${this.baseUrl}/api/v1/log-detection`;
|
|
135
|
+
try {
|
|
136
|
+
const controller = new AbortController();
|
|
137
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
138
|
+
try {
|
|
139
|
+
const response = await fetch(logEndpoint, {
|
|
140
|
+
method: "POST",
|
|
141
|
+
headers: {
|
|
142
|
+
"Content-Type": "application/json",
|
|
143
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
144
|
+
},
|
|
145
|
+
body: JSON.stringify({
|
|
146
|
+
detection: {
|
|
147
|
+
isAgent: input.detection.isAgent,
|
|
148
|
+
confidence: input.detection.confidence,
|
|
149
|
+
agentName: input.detection.agentName,
|
|
150
|
+
agentType: input.detection.agentType,
|
|
151
|
+
detectionClass: input.detection.detectionClass,
|
|
152
|
+
verificationMethod: input.detection.verificationMethod,
|
|
153
|
+
reasons: input.detection.reasons
|
|
154
|
+
},
|
|
155
|
+
context: input.context,
|
|
156
|
+
source: input.source || "gateway"
|
|
157
|
+
}),
|
|
158
|
+
signal: controller.signal
|
|
159
|
+
});
|
|
160
|
+
clearTimeout(timeoutId);
|
|
161
|
+
if (!response.ok && this.debug) {
|
|
162
|
+
console.warn("[AgentShield] Log detection returned non-2xx:", response.status);
|
|
163
|
+
}
|
|
164
|
+
} catch (error) {
|
|
165
|
+
clearTimeout(timeoutId);
|
|
166
|
+
throw error;
|
|
167
|
+
}
|
|
168
|
+
} catch (error) {
|
|
169
|
+
if (this.debug) {
|
|
170
|
+
console.error("[AgentShield] Log detection failed:", error);
|
|
171
|
+
}
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
111
175
|
};
|
|
112
176
|
var clientInstance = null;
|
|
113
177
|
function getAgentShieldClient(config) {
|
|
@@ -151,16 +215,21 @@ function shouldIncludePath(path, includePaths) {
|
|
|
151
215
|
}
|
|
152
216
|
function buildBlockedResponse(decision, config) {
|
|
153
217
|
const status = config.blockedResponse?.status ?? 403;
|
|
154
|
-
const
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
218
|
+
const redirectUrl = config.redirectUrl || decision.redirectUrl;
|
|
219
|
+
const baseMessage = config.blockedResponse?.message ?? decision.message ?? "Access denied";
|
|
220
|
+
const errorMessage = redirectUrl ? `${baseMessage}. Please go to ${redirectUrl}` : baseMessage;
|
|
221
|
+
const message = config.blockedResponse?.message ?? decision.message ?? (redirectUrl ? `AI agents are not permitted on this resource. Please go to ${redirectUrl} for more information.` : "AI agents are not permitted on this resource.");
|
|
222
|
+
const responseBody = {
|
|
223
|
+
error: errorMessage,
|
|
224
|
+
code: "AGENT_BLOCKED",
|
|
225
|
+
reason: decision.reason,
|
|
226
|
+
agentType: decision.agentType,
|
|
227
|
+
message
|
|
228
|
+
};
|
|
229
|
+
if (redirectUrl) {
|
|
230
|
+
responseBody.redirectUrl = redirectUrl;
|
|
231
|
+
}
|
|
232
|
+
const response = server.NextResponse.json(responseBody, { status });
|
|
164
233
|
if (config.blockedResponse?.headers) {
|
|
165
234
|
for (const [key, value] of Object.entries(config.blockedResponse.headers)) {
|
|
166
235
|
response.headers.set(key, value);
|
|
@@ -168,6 +237,9 @@ function buildBlockedResponse(decision, config) {
|
|
|
168
237
|
}
|
|
169
238
|
response.headers.set("X-AgentShield-Action", decision.action);
|
|
170
239
|
response.headers.set("X-AgentShield-Reason", decision.reason);
|
|
240
|
+
if (redirectUrl) {
|
|
241
|
+
response.headers.set("X-AgentShield-Redirect", redirectUrl);
|
|
242
|
+
}
|
|
171
243
|
return response;
|
|
172
244
|
}
|
|
173
245
|
function buildRedirectResponse(request, decision, config) {
|
|
@@ -212,16 +284,20 @@ function withAgentShield(config = {}) {
|
|
|
212
284
|
return server.NextResponse.next();
|
|
213
285
|
}
|
|
214
286
|
try {
|
|
215
|
-
const
|
|
287
|
+
const client2 = getClient();
|
|
288
|
+
const userAgent = request.headers.get("user-agent") || void 0;
|
|
289
|
+
const ipAddress = request.ip || request.headers.get("x-forwarded-for")?.split(",")[0]?.trim() || request.headers.get("x-real-ip") || void 0;
|
|
290
|
+
const result = await client2.enforce({
|
|
216
291
|
headers: Object.fromEntries(request.headers.entries()),
|
|
217
|
-
userAgent
|
|
218
|
-
ipAddress
|
|
292
|
+
userAgent,
|
|
293
|
+
ipAddress,
|
|
219
294
|
path,
|
|
220
295
|
url: request.url,
|
|
221
296
|
method: request.method,
|
|
222
297
|
requestId: request.headers.get("x-request-id") || void 0,
|
|
223
298
|
options: {
|
|
224
|
-
|
|
299
|
+
// Always include detection results for logging (needed when using edge)
|
|
300
|
+
includeDetectionResult: true
|
|
225
301
|
}
|
|
226
302
|
});
|
|
227
303
|
if (!result.success || !result.data) {
|
|
@@ -248,6 +324,16 @@ function withAgentShield(config = {}) {
|
|
|
248
324
|
processingTimeMs: Date.now() - startTime
|
|
249
325
|
});
|
|
250
326
|
}
|
|
327
|
+
if (client2.isUsingEdge() && result.data.detection) {
|
|
328
|
+
client2.logDetection({
|
|
329
|
+
detection: result.data.detection,
|
|
330
|
+
context: { userAgent, ipAddress, path, url: request.url, method: request.method }
|
|
331
|
+
}).catch((err) => {
|
|
332
|
+
if (config.debug) {
|
|
333
|
+
console.error("[AgentShield] Log detection failed:", err);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
}
|
|
251
337
|
if (decision.isAgent && config.onAgentDetected) {
|
|
252
338
|
await config.onAgentDetected(request, decision);
|
|
253
339
|
}
|