@kya-os/checkpoint-express 1.0.0
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 +66 -0
- package/README.md +137 -0
- package/dist/index.d.mts +469 -0
- package/dist/index.d.ts +469 -0
- package/dist/index.js +7520 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +7483 -0
- package/dist/index.mjs.map +1 -0
- package/dist/policy.d.mts +88 -0
- package/dist/policy.d.ts +88 -0
- package/dist/policy.js +74 -0
- package/dist/policy.js.map +1 -0
- package/dist/policy.mjs +49 -0
- package/dist/policy.mjs.map +1 -0
- package/package.json +92 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# @kya-os/checkpoint-express
|
|
2
|
+
|
|
3
|
+
## 1.0.0 — 2026-05-16 (Phase E)
|
|
4
|
+
|
|
5
|
+
### Breaking
|
|
6
|
+
|
|
7
|
+
- **Renamed from `@kya-os/agentshield-express`.** Final deprecation
|
|
8
|
+
stub published as `@kya-os/agentshield-express@0.2.2`; new home is
|
|
9
|
+
this package.
|
|
10
|
+
- **Legacy local-detection chain retired.** `agentShield()`,
|
|
11
|
+
`createAgentShieldMiddleware()`,
|
|
12
|
+
`createEnhancedAgentShieldMiddleware()`, and `applyPolicy()` (and
|
|
13
|
+
the rest of the `policy.ts` enforcement helpers) still export from
|
|
14
|
+
this package — but now throw at runtime with a migration message
|
|
15
|
+
pointing at `withCheckpoint`. The names survive so customers'
|
|
16
|
+
imports don't `ImportError`; calls die loudly.
|
|
17
|
+
- Engine name surfaces as `checkpoint-engine-wasm` in the
|
|
18
|
+
`X-Checkpoint-Engine` response header (engine self-identification;
|
|
19
|
+
same value across all host runtimes — Next.js, Express, .NET,
|
|
20
|
+
future hosts).
|
|
21
|
+
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- **`withCheckpoint(config)`** — the canonical engine-backed
|
|
25
|
+
middleware factory. Replaces every legacy entry point. Signature
|
|
26
|
+
mirrors `@kya-os/checkpoint-nextjs`'s `withCheckpoint` exactly, so
|
|
27
|
+
customers running both runtimes have a single mental model.
|
|
28
|
+
- `CheckpointConfig` type export — minimal config surface
|
|
29
|
+
(`tenantHost`, `enforcementMode`, `argusUrl`, `dashboardUrl`,
|
|
30
|
+
`reputationBaseline`, `adapters`, `onResult`).
|
|
31
|
+
- Cross-runtime parity at the response-adapter layer — the
|
|
32
|
+
`__checkpoint_verdict` cookie is byte-equal to
|
|
33
|
+
`@kya-os/checkpoint-nextjs` (shared `encodeVerdictCookie` primitive
|
|
34
|
+
in `@kya-os/checkpoint-shared/host-adapter`).
|
|
35
|
+
- 19 tests across 4 files: 4 engine-backed smoke tests, 7 response-
|
|
36
|
+
adapter parity tests (mirroring Phase D's adapt.test.ts shape), 5
|
|
37
|
+
structural deletion-gate tests, 3 throw-stub contract tests.
|
|
38
|
+
|
|
39
|
+
### Preserved (per architect §7.2)
|
|
40
|
+
|
|
41
|
+
- `MemoryStorageAdapter`, `RedisStorageAdapter`, `createStorageAdapter`
|
|
42
|
+
remain exported. Compose them with `withCheckpoint` via the
|
|
43
|
+
`onResult` callback for session/event observability (see README).
|
|
44
|
+
- `session-helper.ts` cookie utilities unchanged.
|
|
45
|
+
- All policy-config and detection-result types still re-export from
|
|
46
|
+
`@kya-os/checkpoint-shared` so customer config types keep
|
|
47
|
+
type-checking through the migration window.
|
|
48
|
+
|
|
49
|
+
### Architecture
|
|
50
|
+
|
|
51
|
+
- Verification logic lives in exactly one place — the Rust
|
|
52
|
+
`kya-os-engine` crate, compiled to WASM. This package is plumbing
|
|
53
|
+
only: translate Express `Request` → `IncomingHttpLike`, call
|
|
54
|
+
`verifyRequest`, adapt the verdict to the Express `Response`.
|
|
55
|
+
- `pnpm why @kya-os/agentshield*` from this package returns empty —
|
|
56
|
+
zero transitive dep on the legacy crate names. Engine is the leaf
|
|
57
|
+
crate; legacy crates are tombstones (final deprecation stubs under
|
|
58
|
+
`packages/legacy-deprecation/`).
|
|
59
|
+
|
|
60
|
+
## 0.2.1 and earlier — legacy local-detection chain
|
|
61
|
+
|
|
62
|
+
The earlier versions shipped as `@kya-os/agentshield-express` with a
|
|
63
|
+
TS-side `AgentDetector` pattern matcher, local policy evaluation, and
|
|
64
|
+
combined detection + session-tracking + Redis storage in
|
|
65
|
+
`createEnhancedAgentShieldMiddleware`. See the final deprecation
|
|
66
|
+
stub at `@kya-os/agentshield-express@0.2.2` for migration notes.
|
package/README.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# @kya-os/checkpoint-express
|
|
2
|
+
|
|
3
|
+
Express.js middleware for **Checkpoint** — engine-backed AI agent
|
|
4
|
+
detection and MCP-I verification. Every verification decision flows
|
|
5
|
+
through the Rust `kya-os-engine` via WASM; this package is plumbing
|
|
6
|
+
only (translate request → call engine → apply verdict to response).
|
|
7
|
+
|
|
8
|
+
> **Renamed from `@kya-os/agentshield-express`.** See [migration](#migration) below.
|
|
9
|
+
|
|
10
|
+
## Installation
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @kya-os/checkpoint-express
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Quick Start
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import express from 'express';
|
|
20
|
+
import { withCheckpoint } from '@kya-os/checkpoint-express';
|
|
21
|
+
|
|
22
|
+
const app = express();
|
|
23
|
+
app.use(express.json()); // body-parser — required for MCP-I envelope parsing
|
|
24
|
+
|
|
25
|
+
app.use(
|
|
26
|
+
withCheckpoint({
|
|
27
|
+
tenantHost: 'your.tenant.example',
|
|
28
|
+
})
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
app.get('/', (_req, res) => res.json({ ok: true }));
|
|
32
|
+
app.listen(3000);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
That's the whole API. The engine handles UA pattern detection,
|
|
36
|
+
MCP-I signature verification, scope evaluation, delegation chain
|
|
37
|
+
verification, status-list lookups, and policy evaluation. The
|
|
38
|
+
wrapper translates Express requests, calls the engine, and applies
|
|
39
|
+
the verdict.
|
|
40
|
+
|
|
41
|
+
## Config
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
interface CheckpointConfig {
|
|
45
|
+
tenantHost: string; // your dashboard hostname (drives PolicyEvaluator lookup)
|
|
46
|
+
enforcementMode?: 'enforce' | 'observe'; // default 'enforce'
|
|
47
|
+
argusUrl?: string; // reputation oracle (omit → trust-by-default)
|
|
48
|
+
dashboardUrl?: string; // tenant-policy source (omit → open-by-default)
|
|
49
|
+
reputationBaseline?: number; // anonymous-request baseline; default 1.0
|
|
50
|
+
adapters?: Partial<{
|
|
51
|
+
didResolver;
|
|
52
|
+
statusListCache;
|
|
53
|
+
reputationOracle;
|
|
54
|
+
policyEvaluator;
|
|
55
|
+
}>; // override factory defaults (tests)
|
|
56
|
+
onResult?: (result, req) => void | Promise<void>; // observability hook
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Observability with storage adapters
|
|
61
|
+
|
|
62
|
+
The session-tracking + Redis/Memory event storage from the legacy
|
|
63
|
+
`createEnhancedAgentShieldMiddleware` are now composable primitives.
|
|
64
|
+
Wire them into `withCheckpoint` via the `onResult` callback:
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { withCheckpoint, createStorageAdapter } from '@kya-os/checkpoint-express';
|
|
68
|
+
|
|
69
|
+
const storage = createStorageAdapter({ type: 'redis', ...redisConfig });
|
|
70
|
+
|
|
71
|
+
app.use(
|
|
72
|
+
withCheckpoint({
|
|
73
|
+
tenantHost: 'your.tenant.example',
|
|
74
|
+
onResult: async (result, req) => {
|
|
75
|
+
await storage.recordEvent({
|
|
76
|
+
verdict: result.decision.kind,
|
|
77
|
+
agentDid: result.agentDid,
|
|
78
|
+
ts: Date.now(),
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
})
|
|
82
|
+
);
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Errors thrown inside `onResult` are swallowed so observability
|
|
86
|
+
failures can't break the verdict path.
|
|
87
|
+
|
|
88
|
+
## Response shape
|
|
89
|
+
|
|
90
|
+
The middleware adapts the engine's `Decision` to four response shapes:
|
|
91
|
+
|
|
92
|
+
| Verdict | Action |
|
|
93
|
+
| ---------------- | -------------------------------------------------------------------------------- |
|
|
94
|
+
| Permit / Observe | `next()` — pass through, set verdict cookie + `X-Checkpoint-*` headers |
|
|
95
|
+
| Redirect | `res.redirect(302, target)` |
|
|
96
|
+
| Block + HTML | `res.redirect(302, '/blocked')` — your `/blocked` route reads the verdict cookie |
|
|
97
|
+
| Block + non-HTML | `res.status(<engine-status>).json(body)` (4xx, JSON-API clients) |
|
|
98
|
+
|
|
99
|
+
The `__checkpoint_verdict` cookie is byte-equal to the Next.js
|
|
100
|
+
sibling package (`@kya-os/checkpoint-nextjs`); cross-runtime
|
|
101
|
+
parity at the cookie layer is guaranteed by the shared
|
|
102
|
+
`encodeVerdictCookie` primitive in `@kya-os/checkpoint-shared`.
|
|
103
|
+
|
|
104
|
+
## Migration
|
|
105
|
+
|
|
106
|
+
Coming from `@kya-os/agentshield-express`? Three swaps:
|
|
107
|
+
|
|
108
|
+
```diff
|
|
109
|
+
- "@kya-os/agentshield-express": "^0.2.1"
|
|
110
|
+
+ "@kya-os/checkpoint-express": "^1.0.0"
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
```diff
|
|
114
|
+
- import { agentShield } from '@kya-os/agentshield-express';
|
|
115
|
+
+ import { withCheckpoint } from '@kya-os/checkpoint-express';
|
|
116
|
+
|
|
117
|
+
- app.use(agentShield({ apiKey: process.env.AGENTSHIELD_API_KEY }));
|
|
118
|
+
+ app.use(withCheckpoint({ tenantHost: 'your.tenant.example' }));
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```diff
|
|
122
|
+
// Legacy enhanced middleware
|
|
123
|
+
- import { createEnhancedAgentShieldMiddleware } from '@kya-os/agentshield-express';
|
|
124
|
+
- app.use(createEnhancedAgentShieldMiddleware({ storage: { type: 'redis', ... }, ... }));
|
|
125
|
+
+ // See "Observability with storage adapters" above.
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
The legacy local-detection chain (`agentShield`,
|
|
129
|
+
`createAgentShieldMiddleware`, `createEnhancedAgentShieldMiddleware`,
|
|
130
|
+
`applyPolicy`) was retired in Phase E. The names still export from
|
|
131
|
+
this package — but they throw at runtime with a migration message
|
|
132
|
+
pointing at `withCheckpoint`. Storage adapters and session helpers
|
|
133
|
+
are preserved.
|
|
134
|
+
|
|
135
|
+
## License
|
|
136
|
+
|
|
137
|
+
MIT OR Apache-2.0
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import { Request, RequestHandler, Response, NextFunction } from 'express';
|
|
2
|
+
import { DidResolverAdapter, StatusListCacheAdapter, ReputationOracleAdapter, PolicyEvaluatorAdapter } from '@kya-os/checkpoint-wasm-runtime/adapters';
|
|
3
|
+
import { EnforcementMode, VerifyResult } from '@kya-os/checkpoint-wasm-runtime/engine';
|
|
4
|
+
import { DetectionResult, AgentShieldConfig } from '@kya-os/checkpoint-shared';
|
|
5
|
+
export { DEFAULT_POLICY, ENFORCEMENT_ACTIONS, PolicyConfig, PolicyEvaluationContext, PolicyEvaluationResult, createEvaluationContext, evaluatePolicy } from '@kya-os/checkpoint-shared';
|
|
6
|
+
export { PolicyMiddlewareConfig, applyPolicy, createContextFromDetection, evaluatePolicyForDetection, getPolicy, handlePolicyDecision, sendBlockedResponse, sendRedirectResponse } from './policy.mjs';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* E.1 + E.3 — Express middleware entry: `withCheckpoint(config)`.
|
|
10
|
+
*
|
|
11
|
+
* The host wrapper that composes Phase B adapters + Phase C
|
|
12
|
+
* `verifyRequest` (sync engine) + Phase D translate/adapt into the
|
|
13
|
+
* `withCheckpoint(config)` factory. Mounted under Node-runtime Express
|
|
14
|
+
* servers via `app.use(withCheckpoint({...}))`.
|
|
15
|
+
*
|
|
16
|
+
* Phase E only ships the Node-runtime entry — Express doesn't have an
|
|
17
|
+
* Edge variant (Express runs on Node only). Phase D's edge orchestrator
|
|
18
|
+
* (`verifyRequestEdge`) exists for the Next.js + Vercel Edge use case;
|
|
19
|
+
* Express imports the sync `verifyRequest` directly.
|
|
20
|
+
*
|
|
21
|
+
* **Public API contract (architect § 4.1):**
|
|
22
|
+
*
|
|
23
|
+
* - `withCheckpoint(config)` — factory returning Express middleware.
|
|
24
|
+
* - `CheckpointConfig` — the config shape; new fields are additive.
|
|
25
|
+
*
|
|
26
|
+
* Internal implementation gutted, external contract held. The legacy
|
|
27
|
+
* `agentShield()` / `createAgentShieldMiddleware()` exports remain in
|
|
28
|
+
* the package during the deprecation window (see E.4) — but as
|
|
29
|
+
* throw-stubs with migration messages, not working entry points.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Configuration for `withCheckpoint`.
|
|
34
|
+
*
|
|
35
|
+
* Shape mirrors `checkpoint-nextjs`'s `CheckpointConfig` so customers
|
|
36
|
+
* running both runtimes have a single mental model.
|
|
37
|
+
*/
|
|
38
|
+
interface CheckpointConfig {
|
|
39
|
+
/**
|
|
40
|
+
* Tenant identifier — typically the customer's dashboard hostname
|
|
41
|
+
* (e.g. `acme.checkpoint.example`). The PolicyEvaluator uses this
|
|
42
|
+
* to look up tenant policy from the dashboard.
|
|
43
|
+
*/
|
|
44
|
+
tenantHost: string;
|
|
45
|
+
/**
|
|
46
|
+
* `'enforce'` (default) blocks; `'observe'` passes everything
|
|
47
|
+
* through with `X-Checkpoint-Would-Have-Been` headers. Per Phase 0.2.
|
|
48
|
+
*/
|
|
49
|
+
enforcementMode?: EnforcementMode;
|
|
50
|
+
/**
|
|
51
|
+
* Argus reputation oracle base URL. Omit to use the trust-by-default
|
|
52
|
+
* baseline (reputation defaults to 1.0; orchestrator logs a one-shot
|
|
53
|
+
* warning at first request).
|
|
54
|
+
*/
|
|
55
|
+
argusUrl?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Dashboard base URL for the PolicyEvaluator to fetch tenant policy
|
|
58
|
+
* from. Omit to use the open-by-default tenant policy.
|
|
59
|
+
*/
|
|
60
|
+
dashboardUrl?: string;
|
|
61
|
+
/**
|
|
62
|
+
* Returned to the PolicyEvaluator for anonymous requests (no agent
|
|
63
|
+
* DID). Default 1.0 (trust-by-default).
|
|
64
|
+
*/
|
|
65
|
+
reputationBaseline?: number;
|
|
66
|
+
/**
|
|
67
|
+
* Pre-built adapter instances. Production deployments use the
|
|
68
|
+
* factory-built defaults from `@kya-os/checkpoint-wasm-runtime/
|
|
69
|
+
* adapters`; tests use stubs. The factory composes any provided
|
|
70
|
+
* overrides over defaults — partial overrides are supported.
|
|
71
|
+
*/
|
|
72
|
+
adapters?: Partial<{
|
|
73
|
+
didResolver: DidResolverAdapter;
|
|
74
|
+
statusListCache: StatusListCacheAdapter;
|
|
75
|
+
reputationOracle: ReputationOracleAdapter;
|
|
76
|
+
policyEvaluator: PolicyEvaluatorAdapter;
|
|
77
|
+
}>;
|
|
78
|
+
/**
|
|
79
|
+
* Optional callback for the post-verdict path — fires after every
|
|
80
|
+
* verification, regardless of permit/block, with the full
|
|
81
|
+
* `VerifyResult`. Use for logging, dashboards, telemetry. Errors
|
|
82
|
+
* thrown here are swallowed so user code can't break the middleware
|
|
83
|
+
* response.
|
|
84
|
+
*/
|
|
85
|
+
onResult?: (result: VerifyResult, req: Request) => void | Promise<void>;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Build the Checkpoint middleware. Returns an Express `RequestHandler`
|
|
89
|
+
* suitable for `app.use(withCheckpoint({...}))`.
|
|
90
|
+
*
|
|
91
|
+
* Every verification decision flows through the Rust `kya-os-engine`
|
|
92
|
+
* via WASM. The TS layer translates request shape, calls
|
|
93
|
+
* `verifyRequest`, and applies the verdict to `res` (or calls `next()`
|
|
94
|
+
* for pass-through). No verification logic lives in this file.
|
|
95
|
+
*/
|
|
96
|
+
declare function withCheckpoint(config: CheckpointConfig): RequestHandler;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Express-specific type definitions
|
|
100
|
+
*/
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Express middleware configuration
|
|
104
|
+
*/
|
|
105
|
+
interface ExpressMiddlewareConfig extends AgentShieldConfig {
|
|
106
|
+
/**
|
|
107
|
+
* API key for loading customer policies from AgentShield dashboard
|
|
108
|
+
* When provided, enables policy enforcement (deny lists, allow lists, thresholds)
|
|
109
|
+
*/
|
|
110
|
+
apiKey?: string;
|
|
111
|
+
/**
|
|
112
|
+
* Custom URL for the policy API
|
|
113
|
+
* @default 'https://api.agentshield.io'
|
|
114
|
+
*/
|
|
115
|
+
policyApiUrl?: string;
|
|
116
|
+
/**
|
|
117
|
+
* Action to take when an agent is detected
|
|
118
|
+
*/
|
|
119
|
+
onAgentDetected?: 'block' | 'allow' | 'log';
|
|
120
|
+
/**
|
|
121
|
+
* Custom handler for agent detection
|
|
122
|
+
*/
|
|
123
|
+
onDetection?: (req: Request, res: Response, result: DetectionResult) => void | Promise<void>;
|
|
124
|
+
/**
|
|
125
|
+
* Skip agent detection for certain routes
|
|
126
|
+
*/
|
|
127
|
+
skipPaths?: string[] | RegExp[];
|
|
128
|
+
/**
|
|
129
|
+
* Custom response when blocking agents
|
|
130
|
+
*/
|
|
131
|
+
blockedResponse?: {
|
|
132
|
+
status: number;
|
|
133
|
+
message: string;
|
|
134
|
+
headers?: Record<string, string>;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Enable debug logging
|
|
138
|
+
*/
|
|
139
|
+
debug?: boolean;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Extended Express Request with AgentShield data
|
|
143
|
+
*/
|
|
144
|
+
interface AgentShieldRequest extends Request {
|
|
145
|
+
agentShield?: {
|
|
146
|
+
result: DetectionResult;
|
|
147
|
+
skipped: boolean;
|
|
148
|
+
session?: {
|
|
149
|
+
id: string;
|
|
150
|
+
agent: string;
|
|
151
|
+
confidence: number;
|
|
152
|
+
detectedAt: number;
|
|
153
|
+
expires: number;
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Middleware function type
|
|
159
|
+
*/
|
|
160
|
+
type AgentShieldMiddleware = (req: Request, res: Response, next: NextFunction) => void | Promise<void>;
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Legacy Express middleware — Phase E throw-stub.
|
|
164
|
+
*
|
|
165
|
+
* The local-detection chain (pattern matching → JS-side policy
|
|
166
|
+
* evaluation) was retired in Phase E. Every legacy
|
|
167
|
+
* call site now throws with a migration message pointing at
|
|
168
|
+
* `withCheckpoint()` from `@kya-os/checkpoint-express`.
|
|
169
|
+
*
|
|
170
|
+
* Per Dylan's architect call 2026-05-16: local-detection chain entry
|
|
171
|
+
* points become throw-stubs after the engine-backed replacement ships.
|
|
172
|
+
* The export names survive so customers don't `ImportError` on upgrade
|
|
173
|
+
* — calls throw at runtime with a clear migration path. SaaS-API
|
|
174
|
+
* entry points (`AgentShieldClient`, `client.enforce()`) get a
|
|
175
|
+
* different treatment (rename + preserve); Express had no such surface
|
|
176
|
+
* (audit confirmed 2026-05-16 in the Phase E kickoff brief § "addendum
|
|
177
|
+
* 2026-05-16").
|
|
178
|
+
*
|
|
179
|
+
* @deprecated Use `withCheckpoint` from `@kya-os/checkpoint-express`.
|
|
180
|
+
*/
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @deprecated Throws with a migration message. Use `withCheckpoint` instead.
|
|
184
|
+
*/
|
|
185
|
+
declare function createAgentShieldMiddleware(_config?: Partial<ExpressMiddlewareConfig>): AgentShieldMiddleware;
|
|
186
|
+
/**
|
|
187
|
+
* @deprecated Throws with a migration message. Use `withCheckpoint` instead.
|
|
188
|
+
*/
|
|
189
|
+
declare function agentShield(_config?: Partial<ExpressMiddlewareConfig>): AgentShieldMiddleware;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Session tracking helper for Express
|
|
193
|
+
* Provides graceful degradation of session tracking for non-Next.js environments
|
|
194
|
+
*/
|
|
195
|
+
|
|
196
|
+
interface SessionData {
|
|
197
|
+
id: string;
|
|
198
|
+
agent: string;
|
|
199
|
+
confidence: number;
|
|
200
|
+
detectedAt: number;
|
|
201
|
+
expires: number;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Express-compatible session tracker
|
|
205
|
+
* Uses cookies when available, falls back to headers
|
|
206
|
+
*/
|
|
207
|
+
declare class ExpressSessionTracker {
|
|
208
|
+
private readonly cookieName;
|
|
209
|
+
/**
|
|
210
|
+
* Check for existing session from Express request
|
|
211
|
+
*/
|
|
212
|
+
check(req: Request): SessionData | null;
|
|
213
|
+
/**
|
|
214
|
+
* Track a new session in Express response
|
|
215
|
+
*/
|
|
216
|
+
track(res: Response, result: DetectionResult): void;
|
|
217
|
+
/**
|
|
218
|
+
* Generate a simple ID without crypto dependency
|
|
219
|
+
*/
|
|
220
|
+
private generateId;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Helper to add session tracking to Express middleware
|
|
224
|
+
*/
|
|
225
|
+
declare function withSessionTracking(middleware: (req: Request, res: Response, next: NextFunction) => void | Promise<void>, config?: {
|
|
226
|
+
enabled?: boolean;
|
|
227
|
+
}): (req: Request, res: Response, next: NextFunction) => void | Promise<void>;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Storage adapter types for Express
|
|
231
|
+
* Matches the Next.js storage adapter interface for consistency
|
|
232
|
+
*/
|
|
233
|
+
/**
|
|
234
|
+
* Agent detection event
|
|
235
|
+
*/
|
|
236
|
+
interface AgentDetectionEvent {
|
|
237
|
+
eventId: string;
|
|
238
|
+
sessionId: string;
|
|
239
|
+
timestamp: string;
|
|
240
|
+
agentType: string;
|
|
241
|
+
agentName: string;
|
|
242
|
+
confidence: number;
|
|
243
|
+
path: string;
|
|
244
|
+
userAgent?: string;
|
|
245
|
+
ipAddress?: string;
|
|
246
|
+
method: string;
|
|
247
|
+
detectionReasons: string[];
|
|
248
|
+
verificationMethod: string;
|
|
249
|
+
detectionDetails?: {
|
|
250
|
+
patterns?: Record<string, unknown>;
|
|
251
|
+
behaviors?: Record<string, unknown>;
|
|
252
|
+
fingerprintMatches?: string[];
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Agent session data
|
|
257
|
+
*/
|
|
258
|
+
interface AgentSession {
|
|
259
|
+
sessionId: string;
|
|
260
|
+
ipAddress?: string;
|
|
261
|
+
userAgent?: string;
|
|
262
|
+
agentType: string;
|
|
263
|
+
agentName: string;
|
|
264
|
+
firstSeen: string;
|
|
265
|
+
lastSeen: string;
|
|
266
|
+
eventCount: number;
|
|
267
|
+
paths: string[];
|
|
268
|
+
averageConfidence: number;
|
|
269
|
+
verificationMethods: string[];
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Storage adapter interface
|
|
273
|
+
*/
|
|
274
|
+
interface StorageAdapter {
|
|
275
|
+
/**
|
|
276
|
+
* Store an agent detection event
|
|
277
|
+
*/
|
|
278
|
+
storeEvent(event: AgentDetectionEvent): Promise<void>;
|
|
279
|
+
/**
|
|
280
|
+
* Store or update a session
|
|
281
|
+
*/
|
|
282
|
+
storeSession(session: AgentSession): Promise<void>;
|
|
283
|
+
/**
|
|
284
|
+
* Get events for a session
|
|
285
|
+
*/
|
|
286
|
+
getEvents(sessionId: string, limit?: number): Promise<AgentDetectionEvent[]>;
|
|
287
|
+
/**
|
|
288
|
+
* Get session by ID
|
|
289
|
+
*/
|
|
290
|
+
getSession(sessionId: string): Promise<AgentSession | null>;
|
|
291
|
+
/**
|
|
292
|
+
* Get recent events
|
|
293
|
+
*/
|
|
294
|
+
getRecentEvents(limit?: number): Promise<AgentDetectionEvent[]>;
|
|
295
|
+
/**
|
|
296
|
+
* Get active sessions
|
|
297
|
+
*/
|
|
298
|
+
getActiveSessions(limit?: number): Promise<AgentSession[]>;
|
|
299
|
+
/**
|
|
300
|
+
* Clear old data
|
|
301
|
+
*/
|
|
302
|
+
cleanup?(before: Date): Promise<void>;
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Storage configuration
|
|
306
|
+
*/
|
|
307
|
+
interface StorageConfig {
|
|
308
|
+
type: 'memory' | 'redis' | 'custom';
|
|
309
|
+
ttl?: number;
|
|
310
|
+
redis?: {
|
|
311
|
+
url: string;
|
|
312
|
+
token: string;
|
|
313
|
+
};
|
|
314
|
+
custom?: StorageAdapter;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Legacy enhanced middleware — Phase E throw-stub.
|
|
319
|
+
*
|
|
320
|
+
* `createEnhancedAgentShieldMiddleware` previously bundled local
|
|
321
|
+
* detection + session tracking + Redis/Memory event storage in one
|
|
322
|
+
* factory. Phase E retires the local detection per Dylan's architect
|
|
323
|
+
* call 2026-05-16 (local-detection chain → throw-stub) but preserves
|
|
324
|
+
* the session/Redis observability surface as **composable primitives**:
|
|
325
|
+
*
|
|
326
|
+
* - Storage adapters (`MemoryStorageAdapter`, `RedisStorageAdapter`,
|
|
327
|
+
* `createStorageAdapter`) remain exported from `./storage`.
|
|
328
|
+
* - Session-cookie helpers remain exported from `./session-helper`.
|
|
329
|
+
*
|
|
330
|
+
* Customers who used `createEnhancedAgentShieldMiddleware` for the
|
|
331
|
+
* combined behaviour migrate to `withCheckpoint` + an `onResult`
|
|
332
|
+
* callback that calls into the storage adapter:
|
|
333
|
+
*
|
|
334
|
+
* import { withCheckpoint } from '@kya-os/checkpoint-express';
|
|
335
|
+
* import { createStorageAdapter } from '@kya-os/checkpoint-express';
|
|
336
|
+
*
|
|
337
|
+
* const storage = createStorageAdapter({ type: 'redis', ... });
|
|
338
|
+
*
|
|
339
|
+
* app.use(withCheckpoint({
|
|
340
|
+
* tenantHost: 'your.tenant.example',
|
|
341
|
+
* onResult: async (result, req) => {
|
|
342
|
+
* await storage.recordEvent({
|
|
343
|
+
* verdict: result.decision.kind,
|
|
344
|
+
* agentDid: result.agentDid,
|
|
345
|
+
* ts: Date.now(),
|
|
346
|
+
* // ... whatever the customer's event shape is.
|
|
347
|
+
* });
|
|
348
|
+
* },
|
|
349
|
+
* }));
|
|
350
|
+
*
|
|
351
|
+
* This is the "session/Redis observability" bucket in Dylan's
|
|
352
|
+
* three-bucket decision matrix (Phase E kickoff brief § addendum 2):
|
|
353
|
+
* preserve, refactor to consume engine `Decision` instead of legacy
|
|
354
|
+
* `DetectionResult`. The refactor is customer-side — they wire the
|
|
355
|
+
* adapter into `onResult` themselves. The engine doesn't need to know.
|
|
356
|
+
*
|
|
357
|
+
* @deprecated Throws with a migration message. Compose `withCheckpoint`
|
|
358
|
+
* with the storage adapter directly (example above).
|
|
359
|
+
*/
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Enhanced middleware configuration (legacy). Kept as a type export so
|
|
363
|
+
* customers' config types keep type-checking through the migration
|
|
364
|
+
* window; the factory function below throws at runtime.
|
|
365
|
+
*/
|
|
366
|
+
interface EnhancedMiddlewareConfig {
|
|
367
|
+
/** Storage configuration. */
|
|
368
|
+
storage?: StorageConfig;
|
|
369
|
+
/** Session tracking configuration. */
|
|
370
|
+
sessionTracking?: {
|
|
371
|
+
enabled?: boolean;
|
|
372
|
+
ttl?: number;
|
|
373
|
+
};
|
|
374
|
+
/** Paths to skip detection. */
|
|
375
|
+
skipPaths?: string[];
|
|
376
|
+
/** Action when agent detected. */
|
|
377
|
+
onAgentDetected?: 'block' | 'log' | 'allow';
|
|
378
|
+
/** Custom handler for agent detection. */
|
|
379
|
+
onDetection?: (result: DetectionResult, req: Request) => void | Promise<void>;
|
|
380
|
+
/** Confidence threshold. */
|
|
381
|
+
confidenceThreshold?: number;
|
|
382
|
+
/** Response when blocking. */
|
|
383
|
+
blockedResponse?: {
|
|
384
|
+
status?: number;
|
|
385
|
+
message?: string;
|
|
386
|
+
};
|
|
387
|
+
/** Enable WASM (if available). */
|
|
388
|
+
enableWasm?: boolean;
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* @deprecated Throws with a migration message. Compose `withCheckpoint`
|
|
392
|
+
* with `createStorageAdapter` via the `onResult` callback.
|
|
393
|
+
*/
|
|
394
|
+
declare function createEnhancedAgentShieldMiddleware(_config?: EnhancedMiddlewareConfig): void;
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* In-memory storage adapter for Express
|
|
398
|
+
* Useful for development and testing
|
|
399
|
+
*/
|
|
400
|
+
|
|
401
|
+
declare class MemoryStorageAdapter implements StorageAdapter {
|
|
402
|
+
private events;
|
|
403
|
+
private sessions;
|
|
404
|
+
private eventTimeline;
|
|
405
|
+
private maxEventsPerSession;
|
|
406
|
+
private maxTimelineEvents;
|
|
407
|
+
storeEvent(event: AgentDetectionEvent): Promise<void>;
|
|
408
|
+
storeSession(session: AgentSession): Promise<void>;
|
|
409
|
+
getEvents(sessionId: string, limit?: number): Promise<AgentDetectionEvent[]>;
|
|
410
|
+
getSession(sessionId: string): Promise<AgentSession | null>;
|
|
411
|
+
getRecentEvents(limit?: number): Promise<AgentDetectionEvent[]>;
|
|
412
|
+
getActiveSessions(limit?: number): Promise<AgentSession[]>;
|
|
413
|
+
cleanup(before: Date): Promise<void>;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Redis storage adapter for Express
|
|
418
|
+
* Provides persistent storage for production environments
|
|
419
|
+
*/
|
|
420
|
+
|
|
421
|
+
interface RedisClient {
|
|
422
|
+
set(key: string, value: string, options?: {
|
|
423
|
+
ex?: number;
|
|
424
|
+
}): Promise<string>;
|
|
425
|
+
get(key: string): Promise<string | null>;
|
|
426
|
+
zadd(key: string, ...args: Array<number | string>): Promise<number>;
|
|
427
|
+
zrange(key: string, start: number, stop: number): Promise<string[]>;
|
|
428
|
+
zrevrange(key: string, start: number, stop: number): Promise<string[]>;
|
|
429
|
+
expire(key: string, seconds: number): Promise<number>;
|
|
430
|
+
del(key: string): Promise<number>;
|
|
431
|
+
keys(pattern: string): Promise<string[]>;
|
|
432
|
+
}
|
|
433
|
+
declare class RedisStorageAdapter implements StorageAdapter {
|
|
434
|
+
private redis;
|
|
435
|
+
private prefix;
|
|
436
|
+
private ttl;
|
|
437
|
+
constructor(redis: RedisClient, ttl?: number);
|
|
438
|
+
private getKey;
|
|
439
|
+
storeEvent(event: AgentDetectionEvent): Promise<void>;
|
|
440
|
+
storeSession(session: AgentSession): Promise<void>;
|
|
441
|
+
getEvents(sessionId: string, limit?: number): Promise<AgentDetectionEvent[]>;
|
|
442
|
+
getSession(sessionId: string): Promise<AgentSession | null>;
|
|
443
|
+
getRecentEvents(limit?: number): Promise<AgentDetectionEvent[]>;
|
|
444
|
+
getActiveSessions(limit?: number): Promise<AgentSession[]>;
|
|
445
|
+
cleanup(before: Date): Promise<void>;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
/**
|
|
449
|
+
* Storage adapter exports and factory for Express
|
|
450
|
+
*/
|
|
451
|
+
|
|
452
|
+
/**
|
|
453
|
+
* Create a storage adapter based on configuration
|
|
454
|
+
*/
|
|
455
|
+
declare function createStorageAdapter(config?: StorageConfig): Promise<StorageAdapter>;
|
|
456
|
+
|
|
457
|
+
/**
|
|
458
|
+
* @fileoverview Checkpoint Express Middleware — engine-backed AI agent
|
|
459
|
+
* detection and MCP-I verification.
|
|
460
|
+
*
|
|
461
|
+
* @license MIT OR Apache-2.0
|
|
462
|
+
*/
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Library version
|
|
466
|
+
*/
|
|
467
|
+
declare const VERSION = "1.0.0";
|
|
468
|
+
|
|
469
|
+
export { type AgentDetectionEvent, type AgentSession, type AgentShieldMiddleware, type AgentShieldRequest, type CheckpointConfig, type EnhancedMiddlewareConfig, type ExpressMiddlewareConfig, ExpressSessionTracker, MemoryStorageAdapter, RedisStorageAdapter, type SessionData, type StorageAdapter, type StorageConfig, VERSION, agentShield, createAgentShieldMiddleware, createEnhancedAgentShieldMiddleware, createStorageAdapter, withCheckpoint, withSessionTracking };
|