@kya-os/checkpoint-nextjs 1.0.1 → 1.1.1

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.
@@ -1,10 +1,37 @@
1
1
  import { NextRequest } from 'next/server';
2
2
 
3
3
  /**
4
- * Edge Runtime Compatible WASM Loader for AgentShield
4
+ * Edge Runtime Compatible WASM Loader for Checkpoint
5
5
  *
6
6
  * This module provides a pre-built solution for loading WASM in Edge Runtime.
7
7
  * It requires the WASM file to be manually placed in the project.
8
+ *
9
+ * ## SSOT for pattern detection
10
+ *
11
+ * The fallback `patternDetection` path imports BOTH pattern arrays
12
+ * from `@kya-os/checkpoint-shared/constants/agents`:
13
+ *
14
+ * - `KNOWN_AGENT_PATTERNS` — strict SSOT carved for the server-side
15
+ * classifier (per-agent rows with category + isLegitimate fields).
16
+ * - `INTERACTIVE_AGENT_PATTERNS` — supplement holding interactive-
17
+ * session tokens, generic vendor fallbacks, and the GPT-Crawler
18
+ * entry that lives in seed-agent-types-data.ts (NOT in the strict
19
+ * SSOT).
20
+ *
21
+ * Pre-#2599 this file had a 15-pattern inline subset that diverged
22
+ * from the shared SSOT — the you.com regex was tightened in agents.ts
23
+ * but reverted here. SSOT-Fallback-Drift-1 (this PR) collapsed the
24
+ * inline duplication and moved the supplement into checkpoint-shared
25
+ * so both layers reference the same source. EPIC #2573 (PDM-2) is the
26
+ * future unified-SSOT consolidation that folds the two arrays into
27
+ * one canonical table.
28
+ *
29
+ * ## Naming
30
+ *
31
+ * Old `AgentShield`-prefixed exports are kept as `@deprecated` aliases
32
+ * for one release (`createEdgeAgentShield`, `EdgeRuntimeAgentShield`,
33
+ * `AgentShieldConfig`, `getDefaultAgentShield`). New code should import
34
+ * the `Checkpoint`-prefixed names directly.
8
35
  */
9
36
 
10
37
  interface WasmModule {
@@ -19,7 +46,7 @@ interface DetectionResult {
19
46
  riskLevel?: 'low' | 'medium' | 'high' | 'critical';
20
47
  timestamp: string;
21
48
  }
22
- interface AgentShieldConfig {
49
+ interface EdgeCheckpointConfig {
23
50
  wasmModule?: WebAssembly.Module;
24
51
  enableWasm?: boolean;
25
52
  onAgentDetected?: (result: DetectionResult) => void;
@@ -27,12 +54,12 @@ interface AgentShieldConfig {
27
54
  allowedAgents?: string[];
28
55
  debug?: boolean;
29
56
  }
30
- declare class EdgeRuntimeAgentShield {
57
+ declare class EdgeRuntimeCheckpoint {
31
58
  private wasmInstance;
32
59
  private wasmMemory;
33
60
  private config;
34
61
  private initialized;
35
- constructor(config?: AgentShieldConfig);
62
+ constructor(config?: EdgeCheckpointConfig);
36
63
  init(wasmModule?: WebAssembly.Module): Promise<void>;
37
64
  private readString;
38
65
  private writeString;
@@ -42,9 +69,18 @@ declare class EdgeRuntimeAgentShield {
42
69
  getVerificationMethod(): 'cryptographic' | 'pattern';
43
70
  }
44
71
  /**
45
- * Factory function to create an AgentShield instance for Edge Runtime
72
+ * Factory function to create a Checkpoint instance for Edge Runtime.
46
73
  */
47
- declare function createEdgeAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
48
- declare function getDefaultAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
74
+ declare function createEdgeCheckpoint(config?: EdgeCheckpointConfig): EdgeRuntimeCheckpoint;
75
+ declare function getDefaultEdgeCheckpoint(config?: EdgeCheckpointConfig): EdgeRuntimeCheckpoint;
76
+
77
+ /** @deprecated Renamed to {@link EdgeCheckpointConfig}. */
78
+ type AgentShieldConfig = EdgeCheckpointConfig;
79
+ /** @deprecated Renamed to {@link EdgeRuntimeCheckpoint}. */
80
+ declare const EdgeRuntimeAgentShield: typeof EdgeRuntimeCheckpoint;
81
+ /** @deprecated Renamed to {@link createEdgeCheckpoint}. */
82
+ declare const createEdgeAgentShield: typeof createEdgeCheckpoint;
83
+ /** @deprecated Renamed to {@link getDefaultEdgeCheckpoint}. */
84
+ declare const getDefaultAgentShield: typeof getDefaultEdgeCheckpoint;
49
85
 
50
- export { type AgentShieldConfig, type DetectionResult, type WasmModule, createEdgeAgentShield, getDefaultAgentShield };
86
+ export { type AgentShieldConfig, type DetectionResult, type EdgeCheckpointConfig, EdgeRuntimeAgentShield, EdgeRuntimeCheckpoint, type WasmModule, createEdgeAgentShield, createEdgeCheckpoint, getDefaultAgentShield, getDefaultEdgeCheckpoint };
@@ -1,10 +1,37 @@
1
1
  import { NextRequest } from 'next/server';
2
2
 
3
3
  /**
4
- * Edge Runtime Compatible WASM Loader for AgentShield
4
+ * Edge Runtime Compatible WASM Loader for Checkpoint
5
5
  *
6
6
  * This module provides a pre-built solution for loading WASM in Edge Runtime.
7
7
  * It requires the WASM file to be manually placed in the project.
8
+ *
9
+ * ## SSOT for pattern detection
10
+ *
11
+ * The fallback `patternDetection` path imports BOTH pattern arrays
12
+ * from `@kya-os/checkpoint-shared/constants/agents`:
13
+ *
14
+ * - `KNOWN_AGENT_PATTERNS` — strict SSOT carved for the server-side
15
+ * classifier (per-agent rows with category + isLegitimate fields).
16
+ * - `INTERACTIVE_AGENT_PATTERNS` — supplement holding interactive-
17
+ * session tokens, generic vendor fallbacks, and the GPT-Crawler
18
+ * entry that lives in seed-agent-types-data.ts (NOT in the strict
19
+ * SSOT).
20
+ *
21
+ * Pre-#2599 this file had a 15-pattern inline subset that diverged
22
+ * from the shared SSOT — the you.com regex was tightened in agents.ts
23
+ * but reverted here. SSOT-Fallback-Drift-1 (this PR) collapsed the
24
+ * inline duplication and moved the supplement into checkpoint-shared
25
+ * so both layers reference the same source. EPIC #2573 (PDM-2) is the
26
+ * future unified-SSOT consolidation that folds the two arrays into
27
+ * one canonical table.
28
+ *
29
+ * ## Naming
30
+ *
31
+ * Old `AgentShield`-prefixed exports are kept as `@deprecated` aliases
32
+ * for one release (`createEdgeAgentShield`, `EdgeRuntimeAgentShield`,
33
+ * `AgentShieldConfig`, `getDefaultAgentShield`). New code should import
34
+ * the `Checkpoint`-prefixed names directly.
8
35
  */
9
36
 
10
37
  interface WasmModule {
@@ -19,7 +46,7 @@ interface DetectionResult {
19
46
  riskLevel?: 'low' | 'medium' | 'high' | 'critical';
20
47
  timestamp: string;
21
48
  }
22
- interface AgentShieldConfig {
49
+ interface EdgeCheckpointConfig {
23
50
  wasmModule?: WebAssembly.Module;
24
51
  enableWasm?: boolean;
25
52
  onAgentDetected?: (result: DetectionResult) => void;
@@ -27,12 +54,12 @@ interface AgentShieldConfig {
27
54
  allowedAgents?: string[];
28
55
  debug?: boolean;
29
56
  }
30
- declare class EdgeRuntimeAgentShield {
57
+ declare class EdgeRuntimeCheckpoint {
31
58
  private wasmInstance;
32
59
  private wasmMemory;
33
60
  private config;
34
61
  private initialized;
35
- constructor(config?: AgentShieldConfig);
62
+ constructor(config?: EdgeCheckpointConfig);
36
63
  init(wasmModule?: WebAssembly.Module): Promise<void>;
37
64
  private readString;
38
65
  private writeString;
@@ -42,9 +69,18 @@ declare class EdgeRuntimeAgentShield {
42
69
  getVerificationMethod(): 'cryptographic' | 'pattern';
43
70
  }
44
71
  /**
45
- * Factory function to create an AgentShield instance for Edge Runtime
72
+ * Factory function to create a Checkpoint instance for Edge Runtime.
46
73
  */
47
- declare function createEdgeAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
48
- declare function getDefaultAgentShield(config?: AgentShieldConfig): EdgeRuntimeAgentShield;
74
+ declare function createEdgeCheckpoint(config?: EdgeCheckpointConfig): EdgeRuntimeCheckpoint;
75
+ declare function getDefaultEdgeCheckpoint(config?: EdgeCheckpointConfig): EdgeRuntimeCheckpoint;
76
+
77
+ /** @deprecated Renamed to {@link EdgeCheckpointConfig}. */
78
+ type AgentShieldConfig = EdgeCheckpointConfig;
79
+ /** @deprecated Renamed to {@link EdgeRuntimeCheckpoint}. */
80
+ declare const EdgeRuntimeAgentShield: typeof EdgeRuntimeCheckpoint;
81
+ /** @deprecated Renamed to {@link createEdgeCheckpoint}. */
82
+ declare const createEdgeAgentShield: typeof createEdgeCheckpoint;
83
+ /** @deprecated Renamed to {@link getDefaultEdgeCheckpoint}. */
84
+ declare const getDefaultAgentShield: typeof getDefaultEdgeCheckpoint;
49
85
 
50
- export { type AgentShieldConfig, type DetectionResult, type WasmModule, createEdgeAgentShield, getDefaultAgentShield };
86
+ export { type AgentShieldConfig, type DetectionResult, type EdgeCheckpointConfig, EdgeRuntimeAgentShield, EdgeRuntimeCheckpoint, type WasmModule, createEdgeAgentShield, createEdgeCheckpoint, getDefaultAgentShield, getDefaultEdgeCheckpoint };
@@ -1,5 +1,9 @@
1
1
  'use strict';
2
2
 
3
+ var checkpointShared = require('@kya-os/checkpoint-shared');
4
+
5
+ // src/edge-runtime-loader.ts
6
+
3
7
  // src/utils.ts
4
8
  function getClientIp(request) {
5
9
  const forwardedFor = request.headers.get("x-forwarded-for");
@@ -17,7 +21,40 @@ function getClientIp(request) {
17
21
  }
18
22
 
19
23
  // src/edge-runtime-loader.ts
20
- var EdgeRuntimeAgentShield = class {
24
+ var SUSPICIOUS_HEADER_PREFIXES = ["x-openai-", "x-anthropic-", "x-ai-", "x-llm-", "x-gpt-"];
25
+ function escapeRegex(s) {
26
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
27
+ }
28
+ var TOKEN_REGEX_CACHE = /* @__PURE__ */ new Map();
29
+ function tokenRegex(token) {
30
+ const cached = TOKEN_REGEX_CACHE.get(token);
31
+ if (cached) return cached;
32
+ const regex = new RegExp(`\\b${escapeRegex(token)}\\b`, "i");
33
+ TOKEN_REGEX_CACHE.set(token, regex);
34
+ return regex;
35
+ }
36
+ function matchKnownAgent(lowercasedUa) {
37
+ let best = null;
38
+ for (const entry of checkpointShared.KNOWN_AGENT_PATTERNS) {
39
+ for (const pattern of entry.patterns) {
40
+ if (tokenRegex(pattern).test(lowercasedUa)) {
41
+ if (!best || entry.confidence > best.confidence) {
42
+ best = { name: entry.name, confidence: entry.confidence };
43
+ }
44
+ break;
45
+ }
46
+ }
47
+ }
48
+ for (const { pattern, name, confidence } of checkpointShared.INTERACTIVE_AGENT_PATTERNS) {
49
+ if (pattern.test(lowercasedUa)) {
50
+ if (!best || confidence > best.confidence) {
51
+ best = { name, confidence };
52
+ }
53
+ }
54
+ }
55
+ return best;
56
+ }
57
+ var EdgeRuntimeCheckpoint = class {
21
58
  wasmInstance = null;
22
59
  wasmMemory = null;
23
60
  config;
@@ -49,7 +86,7 @@ var EdgeRuntimeAgentShield = class {
49
86
  this.wasmInstance = await WebAssembly.instantiate(module, imports);
50
87
  this.initialized = true;
51
88
  if (this.config.debug) {
52
- console.log("\u2705 AgentShield WASM initialized in Edge Runtime");
89
+ console.log("\u2705 Checkpoint WASM initialized in Edge Runtime");
53
90
  }
54
91
  } catch (error) {
55
92
  console.warn("\u26A0\uFE0F WASM initialization failed, using pattern detection:", error);
@@ -126,52 +163,29 @@ var EdgeRuntimeAgentShield = class {
126
163
  return this.patternDetection(metadata);
127
164
  }
128
165
  patternDetection(metadata) {
129
- const userAgent = metadata.userAgent.toLowerCase();
130
- const patterns = [
131
- // High confidence - explicit AI identifiers
132
- { pattern: /chatgpt-user/i, name: "ChatGPT", confidence: 0.95 },
133
- { pattern: /claude-web/i, name: "Claude", confidence: 0.95 },
134
- { pattern: /claude-user/i, name: "Claude", confidence: 0.95 },
135
- { pattern: /gpt-crawler/i, name: "GPT Crawler", confidence: 0.95 },
136
- { pattern: /perplexitybot/i, name: "Perplexity", confidence: 0.95 },
137
- { pattern: /perplexity-user/i, name: "Perplexity", confidence: 0.95 },
138
- { pattern: /perplexity-ai/i, name: "Perplexity", confidence: 0.95 },
139
- // Medium-high confidence - company identifiers
140
- { pattern: /anthropic/i, name: "Anthropic", confidence: 0.9 },
141
- { pattern: /openai/i, name: "OpenAI", confidence: 0.9 },
142
- // Medium confidence - product names
143
- { pattern: /copilot/i, name: "GitHub Copilot", confidence: 0.85 },
144
- { pattern: /bard/i, name: "Google Bard", confidence: 0.85 },
145
- { pattern: /gemini/i, name: "Google Gemini", confidence: 0.85 },
146
- { pattern: /perplexity/i, name: "Perplexity", confidence: 0.85 },
147
- // Fallback
148
- { pattern: /\byou\.com\b/i, name: "You.com", confidence: 0.8 },
149
- { pattern: /\bphind\b/i, name: "Phind", confidence: 0.8 }
150
- ];
151
- const suspiciousHeaders = ["x-openai-", "x-anthropic-", "x-ai-", "x-llm-", "x-gpt-"];
166
+ const lowercasedUa = metadata.userAgent.toLowerCase();
152
167
  let headerBoost = 0;
153
- for (const [key] of Object.entries(metadata.headers)) {
154
- if (suspiciousHeaders.some((prefix) => key.toLowerCase().startsWith(prefix))) {
168
+ for (const key of Object.keys(metadata.headers)) {
169
+ if (SUSPICIOUS_HEADER_PREFIXES.some((prefix) => key.toLowerCase().startsWith(prefix))) {
155
170
  headerBoost = 0.1;
156
171
  break;
157
172
  }
158
173
  }
159
- for (const { pattern, name, confidence } of patterns) {
160
- if (pattern.test(userAgent)) {
161
- const finalConfidence = Math.min(confidence + headerBoost, 1);
162
- const result = {
163
- isAgent: true,
164
- confidence: finalConfidence,
165
- agent: name,
166
- verificationMethod: "pattern",
167
- riskLevel: finalConfidence > 0.9 ? "high" : "medium",
168
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
169
- };
170
- if (this.config.onAgentDetected) {
171
- this.config.onAgentDetected(result);
172
- }
173
- return result;
174
+ const match = matchKnownAgent(lowercasedUa);
175
+ if (match) {
176
+ const finalConfidence = Math.min(match.confidence + headerBoost, 1);
177
+ const result = {
178
+ isAgent: true,
179
+ confidence: finalConfidence,
180
+ agent: match.name,
181
+ verificationMethod: "pattern",
182
+ riskLevel: finalConfidence > 0.9 ? "high" : "medium",
183
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
184
+ };
185
+ if (this.config.onAgentDetected) {
186
+ this.config.onAgentDetected(result);
174
187
  }
188
+ return result;
175
189
  }
176
190
  return {
177
191
  isAgent: false,
@@ -187,16 +201,23 @@ var EdgeRuntimeAgentShield = class {
187
201
  return this.wasmInstance ? "cryptographic" : "pattern";
188
202
  }
189
203
  };
190
- function createEdgeAgentShield(config) {
191
- return new EdgeRuntimeAgentShield(config);
204
+ function createEdgeCheckpoint(config) {
205
+ return new EdgeRuntimeCheckpoint(config);
192
206
  }
193
207
  var defaultInstance = null;
194
- function getDefaultAgentShield(config) {
208
+ function getDefaultEdgeCheckpoint(config) {
195
209
  if (!defaultInstance) {
196
- defaultInstance = new EdgeRuntimeAgentShield(config);
210
+ defaultInstance = new EdgeRuntimeCheckpoint(config);
197
211
  }
198
212
  return defaultInstance;
199
213
  }
214
+ var EdgeRuntimeAgentShield = EdgeRuntimeCheckpoint;
215
+ var createEdgeAgentShield = createEdgeCheckpoint;
216
+ var getDefaultAgentShield = getDefaultEdgeCheckpoint;
200
217
 
218
+ exports.EdgeRuntimeAgentShield = EdgeRuntimeAgentShield;
219
+ exports.EdgeRuntimeCheckpoint = EdgeRuntimeCheckpoint;
201
220
  exports.createEdgeAgentShield = createEdgeAgentShield;
221
+ exports.createEdgeCheckpoint = createEdgeCheckpoint;
202
222
  exports.getDefaultAgentShield = getDefaultAgentShield;
223
+ exports.getDefaultEdgeCheckpoint = getDefaultEdgeCheckpoint;
@@ -1,3 +1,7 @@
1
+ import { KNOWN_AGENT_PATTERNS, INTERACTIVE_AGENT_PATTERNS } from '@kya-os/checkpoint-shared';
2
+
3
+ // src/edge-runtime-loader.ts
4
+
1
5
  // src/utils.ts
2
6
  function getClientIp(request) {
3
7
  const forwardedFor = request.headers.get("x-forwarded-for");
@@ -15,7 +19,40 @@ function getClientIp(request) {
15
19
  }
16
20
 
17
21
  // src/edge-runtime-loader.ts
18
- var EdgeRuntimeAgentShield = class {
22
+ var SUSPICIOUS_HEADER_PREFIXES = ["x-openai-", "x-anthropic-", "x-ai-", "x-llm-", "x-gpt-"];
23
+ function escapeRegex(s) {
24
+ return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
25
+ }
26
+ var TOKEN_REGEX_CACHE = /* @__PURE__ */ new Map();
27
+ function tokenRegex(token) {
28
+ const cached = TOKEN_REGEX_CACHE.get(token);
29
+ if (cached) return cached;
30
+ const regex = new RegExp(`\\b${escapeRegex(token)}\\b`, "i");
31
+ TOKEN_REGEX_CACHE.set(token, regex);
32
+ return regex;
33
+ }
34
+ function matchKnownAgent(lowercasedUa) {
35
+ let best = null;
36
+ for (const entry of KNOWN_AGENT_PATTERNS) {
37
+ for (const pattern of entry.patterns) {
38
+ if (tokenRegex(pattern).test(lowercasedUa)) {
39
+ if (!best || entry.confidence > best.confidence) {
40
+ best = { name: entry.name, confidence: entry.confidence };
41
+ }
42
+ break;
43
+ }
44
+ }
45
+ }
46
+ for (const { pattern, name, confidence } of INTERACTIVE_AGENT_PATTERNS) {
47
+ if (pattern.test(lowercasedUa)) {
48
+ if (!best || confidence > best.confidence) {
49
+ best = { name, confidence };
50
+ }
51
+ }
52
+ }
53
+ return best;
54
+ }
55
+ var EdgeRuntimeCheckpoint = class {
19
56
  wasmInstance = null;
20
57
  wasmMemory = null;
21
58
  config;
@@ -47,7 +84,7 @@ var EdgeRuntimeAgentShield = class {
47
84
  this.wasmInstance = await WebAssembly.instantiate(module, imports);
48
85
  this.initialized = true;
49
86
  if (this.config.debug) {
50
- console.log("\u2705 AgentShield WASM initialized in Edge Runtime");
87
+ console.log("\u2705 Checkpoint WASM initialized in Edge Runtime");
51
88
  }
52
89
  } catch (error) {
53
90
  console.warn("\u26A0\uFE0F WASM initialization failed, using pattern detection:", error);
@@ -124,52 +161,29 @@ var EdgeRuntimeAgentShield = class {
124
161
  return this.patternDetection(metadata);
125
162
  }
126
163
  patternDetection(metadata) {
127
- const userAgent = metadata.userAgent.toLowerCase();
128
- const patterns = [
129
- // High confidence - explicit AI identifiers
130
- { pattern: /chatgpt-user/i, name: "ChatGPT", confidence: 0.95 },
131
- { pattern: /claude-web/i, name: "Claude", confidence: 0.95 },
132
- { pattern: /claude-user/i, name: "Claude", confidence: 0.95 },
133
- { pattern: /gpt-crawler/i, name: "GPT Crawler", confidence: 0.95 },
134
- { pattern: /perplexitybot/i, name: "Perplexity", confidence: 0.95 },
135
- { pattern: /perplexity-user/i, name: "Perplexity", confidence: 0.95 },
136
- { pattern: /perplexity-ai/i, name: "Perplexity", confidence: 0.95 },
137
- // Medium-high confidence - company identifiers
138
- { pattern: /anthropic/i, name: "Anthropic", confidence: 0.9 },
139
- { pattern: /openai/i, name: "OpenAI", confidence: 0.9 },
140
- // Medium confidence - product names
141
- { pattern: /copilot/i, name: "GitHub Copilot", confidence: 0.85 },
142
- { pattern: /bard/i, name: "Google Bard", confidence: 0.85 },
143
- { pattern: /gemini/i, name: "Google Gemini", confidence: 0.85 },
144
- { pattern: /perplexity/i, name: "Perplexity", confidence: 0.85 },
145
- // Fallback
146
- { pattern: /\byou\.com\b/i, name: "You.com", confidence: 0.8 },
147
- { pattern: /\bphind\b/i, name: "Phind", confidence: 0.8 }
148
- ];
149
- const suspiciousHeaders = ["x-openai-", "x-anthropic-", "x-ai-", "x-llm-", "x-gpt-"];
164
+ const lowercasedUa = metadata.userAgent.toLowerCase();
150
165
  let headerBoost = 0;
151
- for (const [key] of Object.entries(metadata.headers)) {
152
- if (suspiciousHeaders.some((prefix) => key.toLowerCase().startsWith(prefix))) {
166
+ for (const key of Object.keys(metadata.headers)) {
167
+ if (SUSPICIOUS_HEADER_PREFIXES.some((prefix) => key.toLowerCase().startsWith(prefix))) {
153
168
  headerBoost = 0.1;
154
169
  break;
155
170
  }
156
171
  }
157
- for (const { pattern, name, confidence } of patterns) {
158
- if (pattern.test(userAgent)) {
159
- const finalConfidence = Math.min(confidence + headerBoost, 1);
160
- const result = {
161
- isAgent: true,
162
- confidence: finalConfidence,
163
- agent: name,
164
- verificationMethod: "pattern",
165
- riskLevel: finalConfidence > 0.9 ? "high" : "medium",
166
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
167
- };
168
- if (this.config.onAgentDetected) {
169
- this.config.onAgentDetected(result);
170
- }
171
- return result;
172
+ const match = matchKnownAgent(lowercasedUa);
173
+ if (match) {
174
+ const finalConfidence = Math.min(match.confidence + headerBoost, 1);
175
+ const result = {
176
+ isAgent: true,
177
+ confidence: finalConfidence,
178
+ agent: match.name,
179
+ verificationMethod: "pattern",
180
+ riskLevel: finalConfidence > 0.9 ? "high" : "medium",
181
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
182
+ };
183
+ if (this.config.onAgentDetected) {
184
+ this.config.onAgentDetected(result);
172
185
  }
186
+ return result;
173
187
  }
174
188
  return {
175
189
  isAgent: false,
@@ -185,15 +199,18 @@ var EdgeRuntimeAgentShield = class {
185
199
  return this.wasmInstance ? "cryptographic" : "pattern";
186
200
  }
187
201
  };
188
- function createEdgeAgentShield(config) {
189
- return new EdgeRuntimeAgentShield(config);
202
+ function createEdgeCheckpoint(config) {
203
+ return new EdgeRuntimeCheckpoint(config);
190
204
  }
191
205
  var defaultInstance = null;
192
- function getDefaultAgentShield(config) {
206
+ function getDefaultEdgeCheckpoint(config) {
193
207
  if (!defaultInstance) {
194
- defaultInstance = new EdgeRuntimeAgentShield(config);
208
+ defaultInstance = new EdgeRuntimeCheckpoint(config);
195
209
  }
196
210
  return defaultInstance;
197
211
  }
212
+ var EdgeRuntimeAgentShield = EdgeRuntimeCheckpoint;
213
+ var createEdgeAgentShield = createEdgeCheckpoint;
214
+ var getDefaultAgentShield = getDefaultEdgeCheckpoint;
198
215
 
199
- export { createEdgeAgentShield, getDefaultAgentShield };
216
+ export { EdgeRuntimeAgentShield, EdgeRuntimeCheckpoint, createEdgeAgentShield, createEdgeCheckpoint, getDefaultAgentShield, getDefaultEdgeCheckpoint };
package/dist/index.js CHANGED
@@ -56,21 +56,28 @@ function applyHeaders(res, headers) {
56
56
  }
57
57
 
58
58
  // src/translate.ts
59
- function nextRequestToHttpLike(req) {
59
+ async function nextRequestToHttpLike(req, opts = {}) {
60
60
  const url = new URL(req.url);
61
+ const body = await tryDrainJsonBody(req, opts);
61
62
  return {
62
63
  method: req.method,
63
64
  // Path + query only — orchestrator's URL parsing expects no scheme/host.
64
65
  url: url.pathname + url.search,
65
66
  headers: headersToRecord(req.headers),
66
- // NextRequest.body is a ReadableStream; we don't drain it here.
67
- // The orchestrator routes to PlainHttp when body is falsy, which
68
- // is the right call for streaming middlewares that don't want to
69
- // buffer the request body just to detect agents.
70
- body: null,
67
+ body,
71
68
  remoteAddress: extractRemoteAddress(req)
72
69
  };
73
70
  }
71
+ async function tryDrainJsonBody(req, opts) {
72
+ if (opts.drainJsonBody === false) return null;
73
+ const contentType = req.headers.get("content-type") ?? "";
74
+ if (!contentType.toLowerCase().includes("application/json")) return null;
75
+ try {
76
+ return await req.clone().text();
77
+ } catch {
78
+ return null;
79
+ }
80
+ }
74
81
  function headersToRecord(headers) {
75
82
  const out = {};
76
83
  headers.forEach((value, key) => {
@@ -91,8 +98,9 @@ function extractRemoteAddress(req) {
91
98
  // src/middleware-node.ts
92
99
  function withCheckpoint(config) {
93
100
  const opts = buildVerifyOpts(config);
101
+ const translateOpts = { drainJsonBody: config.drainJsonBody };
94
102
  return async function checkpointMiddleware(req) {
95
- const httpLike = nextRequestToHttpLike(req);
103
+ const httpLike = await nextRequestToHttpLike(req, translateOpts);
96
104
  const result = await orchestrator.verifyRequest(httpLike, opts);
97
105
  await dispatchOnResult(config, result, req);
98
106
  const rendered = orchestrator.renderDecisionAsResponse(result);
@@ -110,7 +118,8 @@ function buildVerifyOpts(config) {
110
118
  tenantHost: config.tenantHost,
111
119
  enforcementMode: config.enforcementMode ?? "enforce",
112
120
  reputationBaseline: config.reputationBaseline,
113
- argusUrl: config.argusUrl
121
+ argusUrl: config.argusUrl,
122
+ legacyEnvelopeFallback: config.legacyEnvelopeFallback ?? false
114
123
  };
115
124
  }
116
125
  async function dispatchOnResult(config, result, req) {
@@ -973,7 +982,13 @@ async function applyPolicy(request, detection, config) {
973
982
  const context = createContextFromDetection(detection, request);
974
983
  const decision = checkpointShared.evaluatePolicy(policy, context);
975
984
  if (config.onPolicyDecision) {
976
- await config.onPolicyDecision(request, decision, context);
985
+ try {
986
+ await config.onPolicyDecision(request, decision, context);
987
+ } catch (error) {
988
+ if (config.debug) {
989
+ console.error("[Checkpoint] onPolicyDecision callback failed:", error);
990
+ }
991
+ }
977
992
  }
978
993
  return await handlePolicyDecision(request, decision, config, detection);
979
994
  } catch (error) {
package/dist/index.mjs CHANGED
@@ -55,21 +55,28 @@ function applyHeaders(res, headers) {
55
55
  }
56
56
 
57
57
  // src/translate.ts
58
- function nextRequestToHttpLike(req) {
58
+ async function nextRequestToHttpLike(req, opts = {}) {
59
59
  const url = new URL(req.url);
60
+ const body = await tryDrainJsonBody(req, opts);
60
61
  return {
61
62
  method: req.method,
62
63
  // Path + query only — orchestrator's URL parsing expects no scheme/host.
63
64
  url: url.pathname + url.search,
64
65
  headers: headersToRecord(req.headers),
65
- // NextRequest.body is a ReadableStream; we don't drain it here.
66
- // The orchestrator routes to PlainHttp when body is falsy, which
67
- // is the right call for streaming middlewares that don't want to
68
- // buffer the request body just to detect agents.
69
- body: null,
66
+ body,
70
67
  remoteAddress: extractRemoteAddress(req)
71
68
  };
72
69
  }
70
+ async function tryDrainJsonBody(req, opts) {
71
+ if (opts.drainJsonBody === false) return null;
72
+ const contentType = req.headers.get("content-type") ?? "";
73
+ if (!contentType.toLowerCase().includes("application/json")) return null;
74
+ try {
75
+ return await req.clone().text();
76
+ } catch {
77
+ return null;
78
+ }
79
+ }
73
80
  function headersToRecord(headers) {
74
81
  const out = {};
75
82
  headers.forEach((value, key) => {
@@ -90,8 +97,9 @@ function extractRemoteAddress(req) {
90
97
  // src/middleware-node.ts
91
98
  function withCheckpoint(config) {
92
99
  const opts = buildVerifyOpts(config);
100
+ const translateOpts = { drainJsonBody: config.drainJsonBody };
93
101
  return async function checkpointMiddleware(req) {
94
- const httpLike = nextRequestToHttpLike(req);
102
+ const httpLike = await nextRequestToHttpLike(req, translateOpts);
95
103
  const result = await verifyRequest(httpLike, opts);
96
104
  await dispatchOnResult(config, result, req);
97
105
  const rendered = renderDecisionAsResponse(result);
@@ -109,7 +117,8 @@ function buildVerifyOpts(config) {
109
117
  tenantHost: config.tenantHost,
110
118
  enforcementMode: config.enforcementMode ?? "enforce",
111
119
  reputationBaseline: config.reputationBaseline,
112
- argusUrl: config.argusUrl
120
+ argusUrl: config.argusUrl,
121
+ legacyEnvelopeFallback: config.legacyEnvelopeFallback ?? false
113
122
  };
114
123
  }
115
124
  async function dispatchOnResult(config, result, req) {
@@ -972,7 +981,13 @@ async function applyPolicy(request, detection, config) {
972
981
  const context = createContextFromDetection(detection, request);
973
982
  const decision = evaluatePolicy(policy, context);
974
983
  if (config.onPolicyDecision) {
975
- await config.onPolicyDecision(request, decision, context);
984
+ try {
985
+ await config.onPolicyDecision(request, decision, context);
986
+ } catch (error) {
987
+ if (config.debug) {
988
+ console.error("[Checkpoint] onPolicyDecision callback failed:", error);
989
+ }
990
+ }
976
991
  }
977
992
  return await handlePolicyDecision(request, decision, config, detection);
978
993
  } catch (error) {
@@ -57,21 +57,28 @@ function applyHeaders(res, headers) {
57
57
  }
58
58
 
59
59
  // src/translate.ts
60
- function nextRequestToHttpLike(req) {
60
+ async function nextRequestToHttpLike(req, opts = {}) {
61
61
  const url = new URL(req.url);
62
+ const body = await tryDrainJsonBody(req, opts);
62
63
  return {
63
64
  method: req.method,
64
65
  // Path + query only — orchestrator's URL parsing expects no scheme/host.
65
66
  url: url.pathname + url.search,
66
67
  headers: headersToRecord(req.headers),
67
- // NextRequest.body is a ReadableStream; we don't drain it here.
68
- // The orchestrator routes to PlainHttp when body is falsy, which
69
- // is the right call for streaming middlewares that don't want to
70
- // buffer the request body just to detect agents.
71
- body: null,
68
+ body,
72
69
  remoteAddress: extractRemoteAddress(req)
73
70
  };
74
71
  }
72
+ async function tryDrainJsonBody(req, opts) {
73
+ if (opts.drainJsonBody === false) return null;
74
+ const contentType = req.headers.get("content-type") ?? "";
75
+ if (!contentType.toLowerCase().includes("application/json")) return null;
76
+ try {
77
+ return await req.clone().text();
78
+ } catch {
79
+ return null;
80
+ }
81
+ }
75
82
  function headersToRecord(headers) {
76
83
  const out = {};
77
84
  headers.forEach((value, key) => {
@@ -101,7 +108,8 @@ function buildVerifyOpts(config) {
101
108
  tenantHost: config.tenantHost,
102
109
  enforcementMode: config.enforcementMode ?? "enforce",
103
110
  reputationBaseline: config.reputationBaseline,
104
- argusUrl: config.argusUrl
111
+ argusUrl: config.argusUrl,
112
+ legacyEnvelopeFallback: config.legacyEnvelopeFallback ?? false
105
113
  };
106
114
  }
107
115
 
@@ -109,8 +117,9 @@ function buildVerifyOpts(config) {
109
117
  function withCheckpoint(config) {
110
118
  void edge.initEngineEdge();
111
119
  const opts = buildVerifyOpts(config);
120
+ const translateOpts = { drainJsonBody: config.drainJsonBody };
112
121
  return async function checkpointMiddlewareEdge(req) {
113
- const httpLike = nextRequestToHttpLike(req);
122
+ const httpLike = await nextRequestToHttpLike(req, translateOpts);
114
123
  const result = await edge.verifyRequestEdge(httpLike, opts);
115
124
  await dispatchOnResult(config, result, req);
116
125
  const rendered = edge.renderDecisionAsResponse(result);