@kya-os/checkpoint-nextjs 1.2.0 → 1.7.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/EDGE_RUNTIME_WASM_SETUP.md +1 -1
  3. package/bin/setup-edge-wasm.js +1 -1
  4. package/dist/api-middleware.d.mts +9 -1
  5. package/dist/api-middleware.d.ts +9 -1
  6. package/dist/api-middleware.js +14 -4
  7. package/dist/api-middleware.mjs +15 -5
  8. package/dist/composed-policy.d.mts +115 -0
  9. package/dist/composed-policy.d.ts +115 -0
  10. package/dist/composed-policy.js +102 -0
  11. package/dist/composed-policy.mjs +96 -0
  12. package/dist/config-DAwIA4DB.d.mts +214 -0
  13. package/dist/config-DyU4l5er.d.ts +214 -0
  14. package/dist/create-middleware.js +0 -2
  15. package/dist/create-middleware.mjs +0 -2
  16. package/dist/edge-runtime-loader.js +3 -1
  17. package/dist/edge-runtime-loader.mjs +3 -1
  18. package/dist/edge-wasm-middleware.d.mts +6 -6
  19. package/dist/edge-wasm-middleware.d.ts +6 -6
  20. package/dist/index.d.mts +6 -14
  21. package/dist/index.d.ts +6 -14
  22. package/dist/index.js +191 -13
  23. package/dist/index.mjs +192 -14
  24. package/dist/middleware-edge.d.mts +7 -3
  25. package/dist/middleware-edge.d.ts +7 -3
  26. package/dist/middleware-edge.js +174 -4
  27. package/dist/middleware-edge.mjs +171 -4
  28. package/dist/middleware-node.d.mts +39 -116
  29. package/dist/middleware-node.d.ts +39 -116
  30. package/dist/middleware-node.js +181 -4
  31. package/dist/middleware-node.mjs +178 -5
  32. package/dist/middleware.d.mts +10 -1
  33. package/dist/middleware.d.ts +10 -1
  34. package/dist/middleware.js +6 -0
  35. package/dist/middleware.mjs +6 -1
  36. package/dist/nodejs-wasm-loader.d.mts +3 -4
  37. package/dist/nodejs-wasm-loader.d.ts +3 -4
  38. package/dist/nodejs-wasm-loader.js +1 -1
  39. package/dist/nodejs-wasm-loader.mjs +1 -1
  40. package/dist/wasm-setup.js +1 -1
  41. package/dist/wasm-setup.mjs +1 -1
  42. package/package.json +4 -9
  43. package/dist/.tsbuildinfo +0 -1
  44. package/dist/signature-verifier.d.mts +0 -33
  45. package/dist/signature-verifier.d.ts +0 -33
  46. package/dist/signature-verifier.js +0 -384
  47. package/dist/signature-verifier.mjs +0 -360
  48. package/dist/wasm-middleware.d.mts +0 -98
  49. package/dist/wasm-middleware.d.ts +0 -98
  50. package/dist/wasm-middleware.js +0 -125
  51. package/dist/wasm-middleware.mjs +0 -121
  52. package/templates/middleware-wasm-100.ts +0 -161
@@ -1,360 +0,0 @@
1
- import * as ed25519 from '@noble/ed25519';
2
- import { sha512 } from '@noble/hashes/sha2.js';
3
-
4
- // src/signature-verifier.ts
5
- ed25519.etc.sha512Sync = (...m) => sha512(ed25519.etc.concatBytes(...m));
6
- var KNOWN_KEYS = {
7
- chatgpt: [
8
- {
9
- kid: "otMqcjr17mGyruktGvJU8oojQTSMHlVm7uO-lrcqbdg",
10
- // ChatGPT's current Ed25519 public key (base64)
11
- // Source: https://chatgpt.com/.well-known/http-message-signatures-directory
12
- publicKey: "7F_3jDlxaquwh291MiACkcS3Opq88NksyHiakzS-Y1g",
13
- validFrom: 1735689600,
14
- // Jan 1, 2025 (nbf from OpenAI)
15
- validUntil: 1769029093
16
- // Jan 21, 2026 (exp from OpenAI)
17
- }
18
- ]
19
- };
20
- var keyCache = /* @__PURE__ */ new Map();
21
- var CACHE_TTL_MS = 5 * 60 * 1e3;
22
- var CACHE_MAX_SIZE = 100;
23
- function getApiBaseUrl() {
24
- if (typeof window !== "undefined") {
25
- return "/api/internal";
26
- }
27
- const baseUrl = process.env.NEXT_PUBLIC_APP_URL || process.env.NEXT_PUBLIC_API_URL || process.env.API_URL || (process.env.VERCEL_URL ? `https://${process.env.VERCEL_URL}` : null);
28
- if (baseUrl) {
29
- return baseUrl.replace(/\/$/, "") + "/api/internal";
30
- }
31
- if (process.env.NODE_ENV !== "production") {
32
- console.warn(
33
- "[Signature] No base URL configured for server-side fetch. Using localhost fallback."
34
- );
35
- return "http://localhost:3000/api/internal";
36
- }
37
- console.error(
38
- "[Signature] CRITICAL: No base URL configured for server-side fetch in production!"
39
- );
40
- return "/api/internal";
41
- }
42
- function cleanupExpiredCache() {
43
- const now = Date.now();
44
- const entriesToDelete = [];
45
- for (const [agent, cached] of keyCache.entries()) {
46
- if (now - cached.cachedAt > CACHE_TTL_MS) {
47
- entriesToDelete.push(agent);
48
- }
49
- }
50
- for (const agent of entriesToDelete) {
51
- keyCache.delete(agent);
52
- }
53
- if (keyCache.size > CACHE_MAX_SIZE) {
54
- const entries = Array.from(keyCache.entries()).map(([agent, cached]) => ({
55
- agent,
56
- cachedAt: cached.cachedAt
57
- }));
58
- entries.sort((a, b) => a.cachedAt - b.cachedAt);
59
- const toRemove = entries.slice(0, keyCache.size - CACHE_MAX_SIZE);
60
- for (const entry of toRemove) {
61
- keyCache.delete(entry.agent);
62
- }
63
- }
64
- }
65
- async function fetchKeysFromApi(agent) {
66
- if (keyCache.size > CACHE_MAX_SIZE) {
67
- cleanupExpiredCache();
68
- }
69
- const cached = keyCache.get(agent);
70
- if (cached && Date.now() - cached.cachedAt < CACHE_TTL_MS) {
71
- return cached.keys;
72
- }
73
- if (typeof fetch === "undefined") {
74
- console.warn("[Signature] fetch() not available in this environment");
75
- return null;
76
- }
77
- try {
78
- const apiBaseUrl = getApiBaseUrl();
79
- const url = `${apiBaseUrl}/signature-keys?agent=${encodeURIComponent(agent)}`;
80
- const response = await fetch(url, {
81
- method: "GET",
82
- headers: {
83
- "Content-Type": "application/json"
84
- },
85
- // 5 second timeout
86
- signal: AbortSignal.timeout(5e3)
87
- });
88
- if (!response.ok) {
89
- console.warn(`[Signature] Failed to fetch keys from API: ${response.status}`);
90
- return null;
91
- }
92
- const data = await response.json();
93
- if (!data.keys || !Array.isArray(data.keys) || data.keys.length === 0) {
94
- console.warn(`[Signature] No keys returned from API for agent: ${agent}`);
95
- return null;
96
- }
97
- keyCache.set(agent, {
98
- keys: data.keys,
99
- cachedAt: Date.now()
100
- });
101
- return data.keys;
102
- } catch (error) {
103
- console.warn("[Signature] Error fetching keys from API, using fallback", {
104
- error: error instanceof Error ? error.message : "Unknown error",
105
- agent
106
- });
107
- return null;
108
- }
109
- }
110
- function isValidAgent(agent) {
111
- return agent in KNOWN_KEYS;
112
- }
113
- async function getKeysForAgent(agent) {
114
- const apiKeys = await fetchKeysFromApi(agent);
115
- if (apiKeys && apiKeys.length > 0) {
116
- return apiKeys;
117
- }
118
- if (isValidAgent(agent)) {
119
- return KNOWN_KEYS[agent];
120
- }
121
- return [];
122
- }
123
- function parseSignatureInput(signatureInput) {
124
- try {
125
- const match = signatureInput.match(/sig1=\((.*?)\);(.+)/);
126
- if (!match) return null;
127
- const [, headersList, params] = match;
128
- const signedHeaders = headersList ? headersList.split(" ").map((h) => h.replace(/"/g, "").trim()).filter((h) => h.length > 0) : [];
129
- const keyidMatch = params ? params.match(/keyid="([^"]+)"/) : null;
130
- const createdMatch = params ? params.match(/created=(\d+)/) : null;
131
- const expiresMatch = params ? params.match(/expires=(\d+)/) : null;
132
- if (!keyidMatch || !keyidMatch[1]) return null;
133
- return {
134
- keyid: keyidMatch[1],
135
- created: createdMatch && createdMatch[1] ? parseInt(createdMatch[1]) : void 0,
136
- expires: expiresMatch && expiresMatch[1] ? parseInt(expiresMatch[1]) : void 0,
137
- signedHeaders
138
- };
139
- } catch (error) {
140
- console.error("[Signature] Failed to parse Signature-Input:", error);
141
- return null;
142
- }
143
- }
144
- function buildSignatureBase(method, path, headers, signedHeaders) {
145
- const components = [];
146
- for (const headerName of signedHeaders) {
147
- let value;
148
- switch (headerName) {
149
- case "@method":
150
- value = method.toUpperCase();
151
- break;
152
- case "@path":
153
- value = path;
154
- break;
155
- case "@authority":
156
- value = headers["host"] || headers["Host"] || "";
157
- break;
158
- default: {
159
- const key = Object.keys(headers).find((k) => k.toLowerCase() === headerName.toLowerCase());
160
- value = key ? headers[key] || "" : "";
161
- break;
162
- }
163
- }
164
- components.push(`"${headerName}": ${value}`);
165
- }
166
- return components.join("\n");
167
- }
168
- function base64ToBytes(base64) {
169
- let standardBase64 = base64.replace(/-/g, "+").replace(/_/g, "/");
170
- const padding = standardBase64.length % 4;
171
- if (padding) {
172
- standardBase64 += "=".repeat(4 - padding);
173
- }
174
- const binaryString = atob(standardBase64);
175
- return Uint8Array.from(binaryString, (c) => c.charCodeAt(0));
176
- }
177
- async function verifyEd25519Signature(publicKeyBase64, signatureBase64, message) {
178
- try {
179
- const publicKeyBytes = base64ToBytes(publicKeyBase64);
180
- const signatureBytes = base64ToBytes(signatureBase64);
181
- const messageBytes = new TextEncoder().encode(message);
182
- if (publicKeyBytes.length !== 32) {
183
- console.error("[Signature] Invalid public key length:", publicKeyBytes.length);
184
- return false;
185
- }
186
- if (signatureBytes.length !== 64) {
187
- console.error("[Signature] Invalid signature length:", signatureBytes.length);
188
- return false;
189
- }
190
- return ed25519.verify(signatureBytes, messageBytes, publicKeyBytes);
191
- } catch (nobleError) {
192
- console.warn("[Signature] @noble/ed25519 failed, trying Web Crypto fallback:", nobleError);
193
- try {
194
- const publicKeyBytes = base64ToBytes(publicKeyBase64);
195
- const signatureBytes = base64ToBytes(signatureBase64);
196
- const messageBytes = new TextEncoder().encode(message);
197
- const publicKey = await crypto.subtle.importKey(
198
- "raw",
199
- publicKeyBytes.buffer,
200
- {
201
- name: "Ed25519",
202
- namedCurve: "Ed25519"
203
- },
204
- false,
205
- ["verify"]
206
- );
207
- return await crypto.subtle.verify(
208
- "Ed25519",
209
- publicKey,
210
- signatureBytes.buffer,
211
- messageBytes
212
- );
213
- } catch (cryptoError) {
214
- console.error("[Signature] Both @noble/ed25519 and Web Crypto failed:", {
215
- nobleError: nobleError instanceof Error ? nobleError.message : "Unknown",
216
- cryptoError: cryptoError instanceof Error ? cryptoError.message : "Unknown"
217
- });
218
- return false;
219
- }
220
- }
221
- }
222
- async function verifyAgentSignature(method, path, headers) {
223
- const signature = headers["signature"] || headers["Signature"];
224
- const signatureInput = headers["signature-input"] || headers["Signature-Input"];
225
- const signatureAgent = headers["signature-agent"] || headers["Signature-Agent"];
226
- if (!signature || !signatureInput) {
227
- return {
228
- isValid: false,
229
- confidence: 0,
230
- reason: "No signature headers present",
231
- verificationMethod: "none"
232
- };
233
- }
234
- const parsed = parseSignatureInput(signatureInput);
235
- if (!parsed) {
236
- return {
237
- isValid: false,
238
- confidence: 0,
239
- reason: "Invalid Signature-Input header",
240
- verificationMethod: "none"
241
- };
242
- }
243
- if (parsed.created) {
244
- const now2 = Math.floor(Date.now() / 1e3);
245
- const age = now2 - parsed.created;
246
- if (age > 300) {
247
- return {
248
- isValid: false,
249
- confidence: 0,
250
- reason: "Signature expired (older than 5 minutes)",
251
- verificationMethod: "none"
252
- };
253
- }
254
- if (age < -30) {
255
- return {
256
- isValid: false,
257
- confidence: 0,
258
- reason: "Signature timestamp is in the future",
259
- verificationMethod: "none"
260
- };
261
- }
262
- }
263
- let agent;
264
- let agentKey;
265
- const isChatGPT = signatureAgent === '"https://chatgpt.com"' || (() => {
266
- try {
267
- const url = new URL(signatureAgent?.replace(/^"|"$/g, "") || "");
268
- return url.hostname === "chatgpt.com" || url.hostname.endsWith(".chatgpt.com");
269
- } catch {
270
- return false;
271
- }
272
- })();
273
- if (isChatGPT) {
274
- agent = "ChatGPT";
275
- agentKey = "chatgpt";
276
- }
277
- if (!agent || !agentKey) {
278
- return {
279
- isValid: false,
280
- confidence: 0,
281
- reason: "Unknown signature agent",
282
- verificationMethod: "none"
283
- };
284
- }
285
- const knownKeys = await getKeysForAgent(agentKey);
286
- if (knownKeys.length === 0) {
287
- return {
288
- isValid: false,
289
- confidence: 0,
290
- reason: "No keys available for agent",
291
- verificationMethod: "none"
292
- };
293
- }
294
- const key = knownKeys.find((k) => k.kid === parsed.keyid);
295
- if (!key) {
296
- return {
297
- isValid: false,
298
- confidence: 0,
299
- reason: `Unknown key ID: ${parsed.keyid}`,
300
- verificationMethod: "none"
301
- };
302
- }
303
- const now = Math.floor(Date.now() / 1e3);
304
- if (now < key.validFrom || now > key.validUntil) {
305
- return {
306
- isValid: false,
307
- confidence: 0,
308
- reason: "Key is not valid at current time",
309
- verificationMethod: "none"
310
- };
311
- }
312
- const signatureBase = buildSignatureBase(method, path, headers, parsed.signedHeaders);
313
- let signatureValue = signature;
314
- if (signatureValue.startsWith("sig1=:")) {
315
- signatureValue = signatureValue.substring(6);
316
- }
317
- if (signatureValue.endsWith(":")) {
318
- signatureValue = signatureValue.slice(0, -1);
319
- }
320
- const isValid = await verifyEd25519Signature(key.publicKey, signatureValue, signatureBase);
321
- if (isValid) {
322
- return {
323
- isValid: true,
324
- agent,
325
- keyid: parsed.keyid,
326
- confidence: 1,
327
- // 100% confidence for valid signature
328
- verificationMethod: "signature"
329
- };
330
- } else {
331
- return {
332
- isValid: false,
333
- confidence: 0,
334
- reason: "Signature verification failed",
335
- verificationMethod: "none"
336
- };
337
- }
338
- }
339
- function hasSignatureHeaders(headers) {
340
- return !!((headers["signature"] || headers["Signature"]) && (headers["signature-input"] || headers["Signature-Input"]));
341
- }
342
- function isChatGPTSignature(headers) {
343
- const signatureAgent = headers["signature-agent"] || headers["Signature-Agent"];
344
- if (!signatureAgent) {
345
- return false;
346
- }
347
- const agentUrlStr = signatureAgent.replace(/^"+|"+$/g, "");
348
- if (agentUrlStr === "https://chatgpt.com") {
349
- return true;
350
- }
351
- try {
352
- const agentUrl = new URL(agentUrlStr);
353
- const allowedHosts = ["chatgpt.com", "www.chatgpt.com"];
354
- return allowedHosts.includes(agentUrl.host);
355
- } catch {
356
- return false;
357
- }
358
- }
359
-
360
- export { hasSignatureHeaders, isChatGPTSignature, verifyAgentSignature };
@@ -1,98 +0,0 @@
1
- import { NextRequest, NextResponse } from 'next/server';
2
-
3
- /**
4
- * WASM-enabled middleware for Next.js with Checkpoint.
5
- *
6
- * **Deprecation notice (AgentDetector-Deletion-1):**
7
- * `createWasmAgentShieldMiddleware` is deprecated as of this patch and
8
- * slated for removal in the next minor. It internally constructs a
9
- * legacy `AgentDetector` and never actually uses the WASM instance for
10
- * detection (the `wasmInstance` arg only bumps confidence by 15%).
11
- * Stage 1 detection now lives in the Rust `kya-os-engine` (PDM-1
12
- * #2560). Migrate to `withCheckpoint` from `@kya-os/checkpoint-nextjs`
13
- * — engine-backed, runs the orchestrator including envelope
14
- * verification.
15
- */
16
-
17
- /** @internal — test-only reset for the one-shot warn latch. */
18
- declare function __resetCreateWasmAgentShieldWarningForTests(): void;
19
- interface WasmDetectionResult {
20
- isAgent: boolean;
21
- isAiCrawler?: boolean;
22
- confidence: number;
23
- agent?: string | undefined;
24
- verificationMethod: 'signature' | 'pattern' | 'none';
25
- riskLevel: 'low' | 'medium' | 'high';
26
- timestamp: string;
27
- }
28
- interface AgentShieldConfig {
29
- onAgentDetected?: (result: WasmDetectionResult) => void | Promise<void>;
30
- blockOnHighConfidence?: boolean;
31
- confidenceThreshold?: number;
32
- skipPaths?: string[];
33
- blockedResponse?: {
34
- status?: number;
35
- message?: string;
36
- headers?: Record<string, string>;
37
- };
38
- }
39
- /**
40
- * @deprecated Wraps the legacy `AgentDetector` class. Will be removed
41
- * in the next minor (AgentDetector-Deletion-2). Migrate to
42
- * `withCheckpoint` from `@kya-os/checkpoint-nextjs` — engine-backed,
43
- * runs the orchestrator including envelope verification.
44
- *
45
- * Create a WASM-enabled Checkpoint middleware (**pattern-detection only**).
46
- *
47
- * **This factory runs UA/header pattern matching only.** It does NOT
48
- * verify MCP-I signed envelopes — no JWS verification, no DID
49
- * resolution, no orchestrator stages. Use it when your only enforcement
50
- * concern is "is this request from a known bot pattern."
51
- *
52
- * **For envelope verification, use {@link withCheckpoint} instead** —
53
- * exported from `@kya-os/checkpoint-nextjs` (Node runtime) or
54
- * `@kya-os/checkpoint-nextjs/edge` (Edge runtime). `withCheckpoint`
55
- * routes every request through the kya-os-engine via WASM and supports
56
- * both `_meta.proof.jws` body envelopes (default) and the legacy
57
- * `KYA-Delegation` header form (opt-in via `legacyEnvelopeFallback`).
58
- * See SDK-Envelope-Plumbing-1 (#2594) for the migration context.
59
- *
60
- * @example pattern-only (this factory)
61
- * ```typescript
62
- * import wasmModule from '@kya-os/checkpoint/wasm?module';
63
- * import { createCheckpointWasmMiddleware } from '@kya-os/checkpoint-nextjs';
64
- *
65
- * const wasmInstance = await WebAssembly.instantiate(wasmModule);
66
- * export const middleware = createCheckpointWasmMiddleware({
67
- * wasmInstance,
68
- * confidenceThreshold: 80,
69
- * });
70
- * ```
71
- *
72
- * @example envelope verification (use `withCheckpoint` instead)
73
- * ```typescript
74
- * import { withCheckpoint } from '@kya-os/checkpoint-nextjs';
75
- *
76
- * export default withCheckpoint({
77
- * tenantHost: 'acme.checkpoint.example',
78
- * legacyEnvelopeFallback: true, // accept `KYA-Delegation` header form
79
- * // drainJsonBody defaults to true; spec-form `_meta.proof.jws` works out of the box
80
- * });
81
- * ```
82
- */
83
- declare function createWasmAgentShieldMiddleware(config: AgentShieldConfig & {
84
- wasmInstance?: WebAssembly.Instance;
85
- }): (request: NextRequest) => Promise<NextResponse<unknown>>;
86
- /**
87
- * Helper to load and instantiate WASM module
88
- * This should be called at the top of your middleware.ts file
89
- *
90
- * @example
91
- * ```typescript
92
- * import wasmModule from '@kya-os/checkpoint/wasm?module';
93
- * const wasmInstance = await instantiateWasm(wasmModule);
94
- * ```
95
- */
96
- declare function instantiateWasm(wasmModule: WebAssembly.Module): Promise<WebAssembly.Instance>;
97
-
98
- export { type AgentShieldConfig, type WasmDetectionResult, __resetCreateWasmAgentShieldWarningForTests, createWasmAgentShieldMiddleware, instantiateWasm };
@@ -1,98 +0,0 @@
1
- import { NextRequest, NextResponse } from 'next/server';
2
-
3
- /**
4
- * WASM-enabled middleware for Next.js with Checkpoint.
5
- *
6
- * **Deprecation notice (AgentDetector-Deletion-1):**
7
- * `createWasmAgentShieldMiddleware` is deprecated as of this patch and
8
- * slated for removal in the next minor. It internally constructs a
9
- * legacy `AgentDetector` and never actually uses the WASM instance for
10
- * detection (the `wasmInstance` arg only bumps confidence by 15%).
11
- * Stage 1 detection now lives in the Rust `kya-os-engine` (PDM-1
12
- * #2560). Migrate to `withCheckpoint` from `@kya-os/checkpoint-nextjs`
13
- * — engine-backed, runs the orchestrator including envelope
14
- * verification.
15
- */
16
-
17
- /** @internal — test-only reset for the one-shot warn latch. */
18
- declare function __resetCreateWasmAgentShieldWarningForTests(): void;
19
- interface WasmDetectionResult {
20
- isAgent: boolean;
21
- isAiCrawler?: boolean;
22
- confidence: number;
23
- agent?: string | undefined;
24
- verificationMethod: 'signature' | 'pattern' | 'none';
25
- riskLevel: 'low' | 'medium' | 'high';
26
- timestamp: string;
27
- }
28
- interface AgentShieldConfig {
29
- onAgentDetected?: (result: WasmDetectionResult) => void | Promise<void>;
30
- blockOnHighConfidence?: boolean;
31
- confidenceThreshold?: number;
32
- skipPaths?: string[];
33
- blockedResponse?: {
34
- status?: number;
35
- message?: string;
36
- headers?: Record<string, string>;
37
- };
38
- }
39
- /**
40
- * @deprecated Wraps the legacy `AgentDetector` class. Will be removed
41
- * in the next minor (AgentDetector-Deletion-2). Migrate to
42
- * `withCheckpoint` from `@kya-os/checkpoint-nextjs` — engine-backed,
43
- * runs the orchestrator including envelope verification.
44
- *
45
- * Create a WASM-enabled Checkpoint middleware (**pattern-detection only**).
46
- *
47
- * **This factory runs UA/header pattern matching only.** It does NOT
48
- * verify MCP-I signed envelopes — no JWS verification, no DID
49
- * resolution, no orchestrator stages. Use it when your only enforcement
50
- * concern is "is this request from a known bot pattern."
51
- *
52
- * **For envelope verification, use {@link withCheckpoint} instead** —
53
- * exported from `@kya-os/checkpoint-nextjs` (Node runtime) or
54
- * `@kya-os/checkpoint-nextjs/edge` (Edge runtime). `withCheckpoint`
55
- * routes every request through the kya-os-engine via WASM and supports
56
- * both `_meta.proof.jws` body envelopes (default) and the legacy
57
- * `KYA-Delegation` header form (opt-in via `legacyEnvelopeFallback`).
58
- * See SDK-Envelope-Plumbing-1 (#2594) for the migration context.
59
- *
60
- * @example pattern-only (this factory)
61
- * ```typescript
62
- * import wasmModule from '@kya-os/checkpoint/wasm?module';
63
- * import { createCheckpointWasmMiddleware } from '@kya-os/checkpoint-nextjs';
64
- *
65
- * const wasmInstance = await WebAssembly.instantiate(wasmModule);
66
- * export const middleware = createCheckpointWasmMiddleware({
67
- * wasmInstance,
68
- * confidenceThreshold: 80,
69
- * });
70
- * ```
71
- *
72
- * @example envelope verification (use `withCheckpoint` instead)
73
- * ```typescript
74
- * import { withCheckpoint } from '@kya-os/checkpoint-nextjs';
75
- *
76
- * export default withCheckpoint({
77
- * tenantHost: 'acme.checkpoint.example',
78
- * legacyEnvelopeFallback: true, // accept `KYA-Delegation` header form
79
- * // drainJsonBody defaults to true; spec-form `_meta.proof.jws` works out of the box
80
- * });
81
- * ```
82
- */
83
- declare function createWasmAgentShieldMiddleware(config: AgentShieldConfig & {
84
- wasmInstance?: WebAssembly.Instance;
85
- }): (request: NextRequest) => Promise<NextResponse<unknown>>;
86
- /**
87
- * Helper to load and instantiate WASM module
88
- * This should be called at the top of your middleware.ts file
89
- *
90
- * @example
91
- * ```typescript
92
- * import wasmModule from '@kya-os/checkpoint/wasm?module';
93
- * const wasmInstance = await instantiateWasm(wasmModule);
94
- * ```
95
- */
96
- declare function instantiateWasm(wasmModule: WebAssembly.Module): Promise<WebAssembly.Instance>;
97
-
98
- export { type AgentShieldConfig, type WasmDetectionResult, __resetCreateWasmAgentShieldWarningForTests, createWasmAgentShieldMiddleware, instantiateWasm };
@@ -1,125 +0,0 @@
1
- 'use strict';
2
-
3
- var server = require('next/server');
4
- var checkpoint = require('@kya-os/checkpoint');
5
-
6
- // src/wasm-middleware.ts
7
-
8
- // src/local-detection-gate.ts
9
- function isDetectedAgentForLocalGate(result) {
10
- return result.isAgent === true;
11
- }
12
- function evaluateLocalDetectionGate(result, config) {
13
- if (!isDetectedAgentForLocalGate(result)) {
14
- return { action: "allow", shouldNotify: false };
15
- }
16
- if ((result.confidence ?? 0) >= config.confidenceThreshold) {
17
- return { action: config.defaultAction, shouldNotify: true };
18
- }
19
- return { action: "allow", shouldNotify: false };
20
- }
21
-
22
- // src/wasm-middleware.ts
23
- var _createWasmAgentShieldWarned = false;
24
- function warnCreateWasmAgentShieldDeprecated() {
25
- if (_createWasmAgentShieldWarned) return;
26
- _createWasmAgentShieldWarned = true;
27
- if (typeof process !== "undefined" && process.env?.NODE_ENV === "production") return;
28
- console.warn(
29
- "[Checkpoint] createWasmAgentShieldMiddleware is deprecated and will be removed in the next minor. It wraps the legacy AgentDetector class; Stage 1 detection now lives in the Rust kya-os-engine (PDM-1). Migrate to `withCheckpoint` from @kya-os/checkpoint-nextjs \u2014 engine-backed and runs envelope verification. See packages/checkpoint-nextjs/CHANGELOG.md for the recipe."
30
- );
31
- }
32
- function __resetCreateWasmAgentShieldWarningForTests() {
33
- _createWasmAgentShieldWarned = false;
34
- }
35
- function createWasmAgentShieldMiddleware(config) {
36
- warnCreateWasmAgentShieldDeprecated();
37
- const {
38
- onAgentDetected,
39
- blockOnHighConfidence = false,
40
- confidenceThreshold = 80,
41
- // Updated to 0-100 scale (was 0.8)
42
- skipPaths = [],
43
- blockedResponse = {
44
- status: 403,
45
- message: "Access denied: AI agent detected",
46
- headers: { "Content-Type": "application/json" }
47
- },
48
- wasmInstance
49
- } = config;
50
- return async function middleware(request) {
51
- const path = request.nextUrl.pathname;
52
- if (skipPaths.some((skip) => path.startsWith(skip))) {
53
- return server.NextResponse.next();
54
- }
55
- try {
56
- const detector = new checkpoint.AgentDetector();
57
- const hasWasm = !!wasmInstance;
58
- const metadata = {
59
- userAgent: request.headers.get("user-agent") || void 0,
60
- ipAddress: request.headers.get("x-forwarded-for") || request.headers.get("x-real-ip") || void 0,
61
- headers: Object.fromEntries(request.headers.entries()),
62
- timestamp: /* @__PURE__ */ new Date()
63
- };
64
- const result = await detector.analyze(metadata);
65
- const enhancedResult = {
66
- isAgent: result.isAgent,
67
- isAiCrawler: result.isAiCrawler,
68
- confidence: hasWasm && result.confidence > 85 ? Math.min(result.confidence * 1.15, 100) : result.confidence,
69
- agent: result.detectedAgent?.name || void 0,
70
- verificationMethod: hasWasm && result.confidence > 85 ? "signature" : "pattern",
71
- // Updated to 0-100 scale
72
- riskLevel: result.confidence > 90 ? "high" : result.confidence > 70 ? "medium" : "low",
73
- // Updated to 0-100 scale (was 0.7)
74
- timestamp: result.timestamp instanceof Date ? result.timestamp.toISOString() : new Date(result.timestamp).toISOString()
75
- };
76
- const decision = evaluateLocalDetectionGate(enhancedResult, {
77
- confidenceThreshold,
78
- defaultAction: blockOnHighConfidence ? "block" : "allow"
79
- });
80
- if (onAgentDetected && isDetectedAgentForLocalGate(enhancedResult)) {
81
- await onAgentDetected(enhancedResult);
82
- }
83
- if (decision.action === "block") {
84
- return server.NextResponse.json(
85
- {
86
- error: blockedResponse.message,
87
- agent: enhancedResult.agent,
88
- confidence: Math.round(enhancedResult.confidence)
89
- },
90
- {
91
- status: blockedResponse.status || 403,
92
- headers: blockedResponse.headers || {}
93
- }
94
- );
95
- }
96
- const response = server.NextResponse.next();
97
- if (enhancedResult.isAgent) {
98
- response.headers.set("X-Agent-Detected", enhancedResult.agent || "unknown");
99
- response.headers.set(
100
- "X-Agent-Confidence",
101
- String(Math.round(enhancedResult.confidence * 100))
102
- );
103
- response.headers.set("X-Agent-Verification", enhancedResult.verificationMethod);
104
- }
105
- return response;
106
- } catch (error) {
107
- console.error("AgentShield middleware error:", error);
108
- return server.NextResponse.next();
109
- }
110
- };
111
- }
112
- async function instantiateWasm(wasmModule) {
113
- try {
114
- const instance = await WebAssembly.instantiate(wasmModule);
115
- console.log("\u2705 AgentShield: WASM module loaded for cryptographic verification");
116
- return instance;
117
- } catch (error) {
118
- console.warn("\u26A0\uFE0F AgentShield: Failed to instantiate WASM module", error);
119
- throw error;
120
- }
121
- }
122
-
123
- exports.__resetCreateWasmAgentShieldWarningForTests = __resetCreateWasmAgentShieldWarningForTests;
124
- exports.createWasmAgentShieldMiddleware = createWasmAgentShieldMiddleware;
125
- exports.instantiateWasm = instantiateWasm;