@kya-os/checkpoint-nextjs 1.1.0 → 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.
- package/CHANGELOG.md +35 -0
- package/dist/edge-runtime-loader.d.mts +44 -8
- package/dist/edge-runtime-loader.d.ts +44 -8
- package/dist/edge-runtime-loader.js +67 -53
- package/dist/edge-runtime-loader.mjs +64 -54
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @kya-os/checkpoint-nextjs
|
|
2
2
|
|
|
3
|
+
## 1.1.1 — 2026-05-17
|
|
4
|
+
|
|
5
|
+
Companion patch to `@kya-os/checkpoint-wasm-runtime@1.1.0`'s
|
|
6
|
+
SDK-WASM-Bundler-Loader-1 fix. **All 1.1.0 users running under Next.js
|
|
7
|
+
Node runtime should upgrade** — `withCheckpoint` couldn't actually be
|
|
8
|
+
deployed under Next.js Node runtime in 1.1.0 due to a Turbopack-
|
|
9
|
+
incompatible URL trick in the wasm-runtime's orchestrator bundle.
|
|
10
|
+
|
|
11
|
+
### Internal change
|
|
12
|
+
|
|
13
|
+
- `@kya-os/checkpoint-wasm-runtime` dep changed from exact `1.0.0`
|
|
14
|
+
pin (the `workspace:*` default) to `^1.1.0` range (via `workspace:^`).
|
|
15
|
+
Fresh installs now pull `wasm-runtime@1.1.0+`, which adds the
|
|
16
|
+
`"node"` export condition routing Next.js Node-runtime bundlers to
|
|
17
|
+
the bundler-clean `orchestrator-node.mjs` entry.
|
|
18
|
+
|
|
19
|
+
### No code or config changes
|
|
20
|
+
|
|
21
|
+
Customer middleware.ts call site is unchanged. Verifying envelopes
|
|
22
|
+
under Next.js Node runtime now works end-to-end:
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { withCheckpoint } from '@kya-os/checkpoint-nextjs';
|
|
26
|
+
|
|
27
|
+
export default withCheckpoint({
|
|
28
|
+
tenantHost: 'acme.checkpoint.example',
|
|
29
|
+
legacyEnvelopeFallback: true,
|
|
30
|
+
});
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
See `@kya-os/checkpoint-wasm-runtime@1.1.0` CHANGELOG for the
|
|
34
|
+
architectural detail.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
3
38
|
## 1.1.0 — 2026-05-17
|
|
4
39
|
|
|
5
40
|
Closes [SDK-Envelope-Plumbing-1 (#2594)](https://github.com/Know-That-Ai/agent-shield/issues/2594).
|
|
@@ -1,10 +1,37 @@
|
|
|
1
1
|
import { NextRequest } from 'next/server';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Edge Runtime Compatible WASM Loader for
|
|
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
|
|
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
|
|
57
|
+
declare class EdgeRuntimeCheckpoint {
|
|
31
58
|
private wasmInstance;
|
|
32
59
|
private wasmMemory;
|
|
33
60
|
private config;
|
|
34
61
|
private initialized;
|
|
35
|
-
constructor(config?:
|
|
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
|
|
72
|
+
* Factory function to create a Checkpoint instance for Edge Runtime.
|
|
46
73
|
*/
|
|
47
|
-
declare function
|
|
48
|
-
declare function
|
|
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
|
|
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
|
|
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
|
|
57
|
+
declare class EdgeRuntimeCheckpoint {
|
|
31
58
|
private wasmInstance;
|
|
32
59
|
private wasmMemory;
|
|
33
60
|
private config;
|
|
34
61
|
private initialized;
|
|
35
|
-
constructor(config?:
|
|
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
|
|
72
|
+
* Factory function to create a Checkpoint instance for Edge Runtime.
|
|
46
73
|
*/
|
|
47
|
-
declare function
|
|
48
|
-
declare function
|
|
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
|
|
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
|
|
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,59 +163,29 @@ var EdgeRuntimeAgentShield = class {
|
|
|
126
163
|
return this.patternDetection(metadata);
|
|
127
164
|
}
|
|
128
165
|
patternDetection(metadata) {
|
|
129
|
-
const
|
|
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
|
-
// UA-context-only pattern — `\b` is the correct anchor for UA
|
|
149
|
-
// substring matching. PR #2591's tightened `[\s;()]` form
|
|
150
|
-
// dropped `/`, which broke legit UA shapes like `you.com/1.0`
|
|
151
|
-
// and `+https://you.com)` (cursor catch on the same PR — see
|
|
152
|
-
// sibling agents.ts comment for the full rationale + UA shapes).
|
|
153
|
-
// CodeQL js/regex/missing-regexp-anchor speculates about URL
|
|
154
|
-
// misuse; this codebase only applies the pattern to UA strings.
|
|
155
|
-
{ pattern: /\byou\.com\b/i, name: "You.com", confidence: 0.8 },
|
|
156
|
-
{ pattern: /\bphind\b/i, name: "Phind", confidence: 0.8 }
|
|
157
|
-
];
|
|
158
|
-
const suspiciousHeaders = ["x-openai-", "x-anthropic-", "x-ai-", "x-llm-", "x-gpt-"];
|
|
166
|
+
const lowercasedUa = metadata.userAgent.toLowerCase();
|
|
159
167
|
let headerBoost = 0;
|
|
160
|
-
for (const
|
|
161
|
-
if (
|
|
168
|
+
for (const key of Object.keys(metadata.headers)) {
|
|
169
|
+
if (SUSPICIOUS_HEADER_PREFIXES.some((prefix) => key.toLowerCase().startsWith(prefix))) {
|
|
162
170
|
headerBoost = 0.1;
|
|
163
171
|
break;
|
|
164
172
|
}
|
|
165
173
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
}
|
|
180
|
-
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);
|
|
181
187
|
}
|
|
188
|
+
return result;
|
|
182
189
|
}
|
|
183
190
|
return {
|
|
184
191
|
isAgent: false,
|
|
@@ -194,16 +201,23 @@ var EdgeRuntimeAgentShield = class {
|
|
|
194
201
|
return this.wasmInstance ? "cryptographic" : "pattern";
|
|
195
202
|
}
|
|
196
203
|
};
|
|
197
|
-
function
|
|
198
|
-
return new
|
|
204
|
+
function createEdgeCheckpoint(config) {
|
|
205
|
+
return new EdgeRuntimeCheckpoint(config);
|
|
199
206
|
}
|
|
200
207
|
var defaultInstance = null;
|
|
201
|
-
function
|
|
208
|
+
function getDefaultEdgeCheckpoint(config) {
|
|
202
209
|
if (!defaultInstance) {
|
|
203
|
-
defaultInstance = new
|
|
210
|
+
defaultInstance = new EdgeRuntimeCheckpoint(config);
|
|
204
211
|
}
|
|
205
212
|
return defaultInstance;
|
|
206
213
|
}
|
|
214
|
+
var EdgeRuntimeAgentShield = EdgeRuntimeCheckpoint;
|
|
215
|
+
var createEdgeAgentShield = createEdgeCheckpoint;
|
|
216
|
+
var getDefaultAgentShield = getDefaultEdgeCheckpoint;
|
|
207
217
|
|
|
218
|
+
exports.EdgeRuntimeAgentShield = EdgeRuntimeAgentShield;
|
|
219
|
+
exports.EdgeRuntimeCheckpoint = EdgeRuntimeCheckpoint;
|
|
208
220
|
exports.createEdgeAgentShield = createEdgeAgentShield;
|
|
221
|
+
exports.createEdgeCheckpoint = createEdgeCheckpoint;
|
|
209
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
|
|
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
|
|
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,59 +161,29 @@ var EdgeRuntimeAgentShield = class {
|
|
|
124
161
|
return this.patternDetection(metadata);
|
|
125
162
|
}
|
|
126
163
|
patternDetection(metadata) {
|
|
127
|
-
const
|
|
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
|
-
// UA-context-only pattern — `\b` is the correct anchor for UA
|
|
147
|
-
// substring matching. PR #2591's tightened `[\s;()]` form
|
|
148
|
-
// dropped `/`, which broke legit UA shapes like `you.com/1.0`
|
|
149
|
-
// and `+https://you.com)` (cursor catch on the same PR — see
|
|
150
|
-
// sibling agents.ts comment for the full rationale + UA shapes).
|
|
151
|
-
// CodeQL js/regex/missing-regexp-anchor speculates about URL
|
|
152
|
-
// misuse; this codebase only applies the pattern to UA strings.
|
|
153
|
-
{ pattern: /\byou\.com\b/i, name: "You.com", confidence: 0.8 },
|
|
154
|
-
{ pattern: /\bphind\b/i, name: "Phind", confidence: 0.8 }
|
|
155
|
-
];
|
|
156
|
-
const suspiciousHeaders = ["x-openai-", "x-anthropic-", "x-ai-", "x-llm-", "x-gpt-"];
|
|
164
|
+
const lowercasedUa = metadata.userAgent.toLowerCase();
|
|
157
165
|
let headerBoost = 0;
|
|
158
|
-
for (const
|
|
159
|
-
if (
|
|
166
|
+
for (const key of Object.keys(metadata.headers)) {
|
|
167
|
+
if (SUSPICIOUS_HEADER_PREFIXES.some((prefix) => key.toLowerCase().startsWith(prefix))) {
|
|
160
168
|
headerBoost = 0.1;
|
|
161
169
|
break;
|
|
162
170
|
}
|
|
163
171
|
}
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
}
|
|
178
|
-
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);
|
|
179
185
|
}
|
|
186
|
+
return result;
|
|
180
187
|
}
|
|
181
188
|
return {
|
|
182
189
|
isAgent: false,
|
|
@@ -192,15 +199,18 @@ var EdgeRuntimeAgentShield = class {
|
|
|
192
199
|
return this.wasmInstance ? "cryptographic" : "pattern";
|
|
193
200
|
}
|
|
194
201
|
};
|
|
195
|
-
function
|
|
196
|
-
return new
|
|
202
|
+
function createEdgeCheckpoint(config) {
|
|
203
|
+
return new EdgeRuntimeCheckpoint(config);
|
|
197
204
|
}
|
|
198
205
|
var defaultInstance = null;
|
|
199
|
-
function
|
|
206
|
+
function getDefaultEdgeCheckpoint(config) {
|
|
200
207
|
if (!defaultInstance) {
|
|
201
|
-
defaultInstance = new
|
|
208
|
+
defaultInstance = new EdgeRuntimeCheckpoint(config);
|
|
202
209
|
}
|
|
203
210
|
return defaultInstance;
|
|
204
211
|
}
|
|
212
|
+
var EdgeRuntimeAgentShield = EdgeRuntimeCheckpoint;
|
|
213
|
+
var createEdgeAgentShield = createEdgeCheckpoint;
|
|
214
|
+
var getDefaultAgentShield = getDefaultEdgeCheckpoint;
|
|
205
215
|
|
|
206
|
-
export { createEdgeAgentShield, getDefaultAgentShield };
|
|
216
|
+
export { EdgeRuntimeAgentShield, EdgeRuntimeCheckpoint, createEdgeAgentShield, createEdgeCheckpoint, getDefaultAgentShield, getDefaultEdgeCheckpoint };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kya-os/checkpoint-nextjs",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Checkpoint Next.js middleware for AI agent detection (formerly @kya-os/agentshield-nextjs)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"nextjs",
|
|
@@ -135,8 +135,8 @@
|
|
|
135
135
|
"@noble/ed25519": "^2.2.3",
|
|
136
136
|
"@noble/hashes": "^2.0.1",
|
|
137
137
|
"@kya-os/checkpoint": "1.0.0",
|
|
138
|
-
"@kya-os/checkpoint-
|
|
139
|
-
"@kya-os/checkpoint-
|
|
138
|
+
"@kya-os/checkpoint-shared": "1.0.0",
|
|
139
|
+
"@kya-os/checkpoint-wasm-runtime": "^1.1.0"
|
|
140
140
|
},
|
|
141
141
|
"scripts": {
|
|
142
142
|
"build": "tsup",
|