@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
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { CheckpointConfig, withCheckpoint } from './middleware-node.js';
1
+ export { VERSION, withCheckpoint } from './middleware-node.js';
2
2
  export { createAgentShieldMiddleware, createAgentShieldMiddleware as createMiddleware } from './create-middleware.js';
3
3
  export { AgentDetectionEvent, AgentSession, AgentShieldMiddlewareConfig, CheckpointApiMiddlewareConfig, EnhancedMiddlewareConfig, StorageAdapter, StorageConfig, agentShieldMiddleware, createEnhancedAgentShieldMiddleware, withAgentShield, withCheckpointApi } from './api-middleware.js';
4
4
  export { createAgentShieldMiddleware as createAgentShieldMiddlewareBase } from './middleware.js';
@@ -6,20 +6,12 @@ export { EdgeSessionTracker, SessionData, SessionTrackingConfig, StatelessSessio
6
6
  export { AgentShieldClient, AgentShieldClientConfig, CheckpointApiClient, CheckpointApiClientConfig, EnforceInput, EnforceResponse, EnforcementDecision, LogDetectionInput, getAgentShieldClient, getCheckpointApiClient, resetAgentShieldClient, resetCheckpointApiClient } from './api-client.js';
7
7
  export { A as AgentShieldRequest, D as DetectionContext, N as NextJSMiddlewareConfig } from './types-D9RQvPNy.js';
8
8
  export { NextJSPolicyMiddlewareConfig, PolicyMiddlewareConfig, applyPolicy, buildBlockedResponse as buildPolicyBlockedResponse, buildRedirectResponse as buildPolicyRedirectResponse, createContextFromDetection, evaluatePolicyForDetection, getPolicy, handlePolicyDecision } from './policy.js';
9
+ export { C as CheckpointConfig } from './config-DyU4l5er.js';
9
10
  export { DEFAULT_POLICY, ENFORCEMENT_ACTIONS, EnforcementAction, PolicyConfig, PolicyEvaluationContext, PolicyEvaluationResult, createEvaluationContext, evaluatePolicy } from '@kya-os/checkpoint-shared';
11
+ import '@kya-os/checkpoint-wasm-runtime/engine';
10
12
  import '@kya-os/checkpoint-wasm-runtime/adapters';
11
13
  import 'next/server';
12
- import '@kya-os/checkpoint-wasm-runtime/engine';
14
+ import '@kya-os/checkpoint-wasm-runtime/reporter';
15
+ import './composed-policy.js';
16
+ import '@kya-os/checkpoint-wasm-runtime/composed-policy';
13
17
  import '@kya-os/checkpoint';
14
-
15
- /**
16
- * @fileoverview Checkpoint Next.js Integration
17
- * @license MIT OR Apache-2.0
18
- */
19
-
20
- /**
21
- * Library version
22
- */
23
- declare const VERSION = "0.1.0";
24
-
25
- export { VERSION };
package/dist/index.js CHANGED
@@ -2,8 +2,10 @@
2
2
 
3
3
  var orchestrator = require('@kya-os/checkpoint-wasm-runtime/orchestrator');
4
4
  var adapters = require('@kya-os/checkpoint-wasm-runtime/adapters');
5
- var server = require('next/server');
5
+ var reporter = require('@kya-os/checkpoint-wasm-runtime/reporter');
6
6
  var checkpointShared = require('@kya-os/checkpoint-shared');
7
+ var server = require('next/server');
8
+ var composedPolicy = require('@kya-os/checkpoint-wasm-runtime/composed-policy');
7
9
 
8
10
  // src/middleware-node.ts
9
11
  function adaptToNextResponse(rendered, req) {
@@ -54,6 +56,96 @@ function applyHeaders(res, headers) {
54
56
  res.headers.set(key, value);
55
57
  }
56
58
  }
59
+ var DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
60
+ var NOOP_LOGGER = {
61
+ shadowDivergence: () => {
62
+ },
63
+ evaluationError: () => {
64
+ }
65
+ };
66
+ function makeComposedPolicyContext(opts) {
67
+ const { projectId, fetcher } = opts;
68
+ const cache = composedPolicy.makeComposedPolicyCache({ compile: opts.compile, cacheMax: opts.cacheMax });
69
+ const logger = opts.logger ?? NOOP_LOGGER;
70
+ return {
71
+ async apply(result, path) {
72
+ const structured = { decision: result.decision, acted: false };
73
+ const policy = await fetcher.getPolicy(projectId);
74
+ const outcome = await composedPolicy.evaluateComposedPolicy({
75
+ cache,
76
+ projectId,
77
+ flags: {
78
+ policyLanguage: policy.policyLanguage,
79
+ policySourceText: policy.policySourceText,
80
+ engineEnforcementEnabled: policy.engineEnforcementEnabled,
81
+ enabled: policy.enabled
82
+ },
83
+ authorizeInput: composedPolicy.verifyResultToAuthorizeInput(result, { tenantId: projectId, path }),
84
+ baselineDecisionKind: result.decision.kind
85
+ });
86
+ if ((outcome.status === "acting" || outcome.status === "shadow") && outcome.diverged) {
87
+ logger.shadowDivergence({
88
+ projectId,
89
+ path,
90
+ engineDecision: outcome.engineDecision.kind,
91
+ structuredDecision: result.decision.kind,
92
+ detectionClass: result.detectionDetail.detectionClass.type,
93
+ verificationMethod: result.detectionDetail.verificationMethod,
94
+ confidence: result.detectionDetail.confidence,
95
+ agentName: result.detectionDetail.detectedAgent?.name
96
+ });
97
+ }
98
+ if (outcome.status === "error") {
99
+ logger.evaluationError(projectId, outcome.error);
100
+ return structured;
101
+ }
102
+ if (outcome.status === "acting") {
103
+ return {
104
+ decision: outcome.engineDecision,
105
+ acted: true,
106
+ // Echo the SSOT revision pin with the decision it produced (#3246
107
+ // PR5). Conditional spread: absent upstream stays absent here.
108
+ ...policy.policySourceHash ? { composedBlobHash: policy.policySourceHash } : {}
109
+ };
110
+ }
111
+ return structured;
112
+ },
113
+ async trustedDelegationRoots() {
114
+ const policy = await fetcher.getPolicy(projectId);
115
+ return policy.trustedDelegationRoots ?? [];
116
+ }
117
+ };
118
+ }
119
+ async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
120
+ if (!resolver) return void 0;
121
+ if (!checkpointShared.requestCarriesDelegationProof(headers)) return void 0;
122
+ const roots = await resolver();
123
+ return roots.length > 0 ? roots : void 0;
124
+ }
125
+ async function applyComposedPolicy(context, result, path) {
126
+ if (!context) return;
127
+ try {
128
+ const outcome = await context.apply(result, path);
129
+ if (outcome.acted) {
130
+ result.decision = outcome.decision;
131
+ if (outcome.composedBlobHash) {
132
+ result.composedBlobHash = outcome.composedBlobHash;
133
+ }
134
+ }
135
+ } catch {
136
+ }
137
+ }
138
+ var consoleComposedPolicyLogger = {
139
+ shadowDivergence(info) {
140
+ console.warn("[checkpoint/composed-policy] shadow-divergence", info);
141
+ },
142
+ evaluationError(projectId, error) {
143
+ console.error(
144
+ `[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
145
+ error
146
+ );
147
+ }
148
+ };
57
149
 
58
150
  // src/translate.ts
59
151
  async function nextRequestToHttpLike(req, opts = {}) {
@@ -98,15 +190,96 @@ function extractRemoteAddress(req) {
98
190
  // src/middleware-node.ts
99
191
  function withCheckpoint(config) {
100
192
  const opts = buildVerifyOpts(config);
193
+ const reporter = buildReporter(config);
194
+ const composed = buildComposedContext(config);
195
+ const trustedRootsResolver = buildTrustedRootsResolver(config, composed);
101
196
  const translateOpts = { drainJsonBody: config.drainJsonBody };
102
- return async function checkpointMiddleware(req) {
197
+ return async function checkpointMiddleware(req, event) {
103
198
  const httpLike = await nextRequestToHttpLike(req, translateOpts);
104
- const result = await orchestrator.verifyRequest(httpLike, opts);
199
+ const trustedDelegationRoots = await resolveTrustedDelegationRootsForRequest(
200
+ trustedRootsResolver,
201
+ req.headers
202
+ );
203
+ const result = await orchestrator.verifyRequest(
204
+ httpLike,
205
+ trustedDelegationRoots ? { ...opts, trustedDelegationRoots } : opts
206
+ );
207
+ await applyComposedPolicy(composed, result, req.nextUrl.pathname);
208
+ if (reporter) {
209
+ const reportPromise = reporter(result, extractReporterContext(req));
210
+ if (event) {
211
+ event.waitUntil(reportPromise);
212
+ }
213
+ }
105
214
  await dispatchOnResult(config, result, req);
106
- const rendered = orchestrator.renderDecisionAsResponse(result);
215
+ const bodyReadable200 = checkpointShared.selectBodyReadable200(
216
+ config.delegationChallengeMode ?? "spec-401",
217
+ req.headers,
218
+ result.detectionDetail.detectionClass
219
+ );
220
+ const rendered = orchestrator.renderDecisionAsResponse(result, { bodyReadable200 });
107
221
  return adaptToNextResponse(rendered, req);
108
222
  };
109
223
  }
224
+ var SDK_NAME = "@kya-os/checkpoint-nextjs";
225
+ var VERSION = "1.7.1";
226
+ function buildReporter(config, runtime = "node") {
227
+ if (!config.apiKey) return null;
228
+ return reporter.makeDetectionReporter({
229
+ apiKey: config.apiKey,
230
+ baseUrl: config.baseUrl,
231
+ debug: config.debug,
232
+ // Self-identify (incl. node-vs-edge) so the dashboard can version-gate
233
+ // enforcement. Next.js EDGE composed enforcement is opt-in (needs
234
+ // `cedarWasmModule`), so the dashboard shows it as opt-in, never "Enforcing".
235
+ sdk: { name: SDK_NAME, version: VERSION, runtime }
236
+ });
237
+ }
238
+ function buildTrustedRootsResolver(config, composed) {
239
+ if (composed?.trustedDelegationRoots) {
240
+ return () => composed.trustedDelegationRoots();
241
+ }
242
+ if (!config.projectId) return null;
243
+ const fetcher = new checkpointShared.PolicyFetcher({
244
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
245
+ apiKey: config.apiKey,
246
+ cacheTtlSeconds: config.policyCacheTtlSeconds
247
+ });
248
+ const projectId = config.projectId;
249
+ return async () => (await fetcher.getPolicy(projectId)).trustedDelegationRoots ?? [];
250
+ }
251
+ function buildComposedContext(config) {
252
+ if (config.composedPolicyEnforcer) return config.composedPolicyEnforcer;
253
+ if (!config.projectId) return null;
254
+ return makeComposedPolicyContext({
255
+ projectId: config.projectId,
256
+ fetcher: new checkpointShared.PolicyFetcher({
257
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
258
+ apiKey: config.apiKey,
259
+ cacheTtlSeconds: config.policyCacheTtlSeconds
260
+ }),
261
+ // LAZY dynamic import — NOT a top-level `import` — so the node-only
262
+ // `./policy` glue (`createRequire`/`fs` at module load) is never pulled into
263
+ // the Edge bundle. `middleware-edge.ts` imports helpers from this file, so a
264
+ // top-level `./policy` import would surface as a side-effect import in the
265
+ // edge bundle and boot-fail on Vercel edge. The import is cached after first
266
+ // call; the core's single-flight cache wraps the (now async) compile.
267
+ compile: async (_language, source) => {
268
+ const { createPolicyEvaluator } = await import('@kya-os/checkpoint-wasm-runtime/policy');
269
+ return createPolicyEvaluator(source);
270
+ },
271
+ logger: config.debug ? consoleComposedPolicyLogger : void 0
272
+ });
273
+ }
274
+ function extractReporterContext(req) {
275
+ return {
276
+ userAgent: req.headers.get("user-agent") ?? void 0,
277
+ ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0,
278
+ path: req.nextUrl.pathname,
279
+ url: req.nextUrl.href,
280
+ method: req.method
281
+ };
282
+ }
110
283
  function buildVerifyOpts(config) {
111
284
  const overrides = config.adapters ?? {};
112
285
  return {
@@ -130,8 +303,6 @@ async function dispatchOnResult(config, result, req) {
130
303
  } catch {
131
304
  }
132
305
  }
133
-
134
- // src/middleware.ts
135
306
  var MIGRATION_ERROR = "@kya-os/checkpoint-nextjs's `createAgentShieldMiddleware` / `agentShield` were deleted in Phase D (engine consolidation). The 600-line TS pattern matcher that backed them is gone. Migrate to `withCheckpoint` from `@kya-os/checkpoint-nextjs` (Node runtime) or `@kya-os/checkpoint-nextjs/edge` (Edge runtime). See packages/checkpoint-nextjs/CHANGELOG.md (1.0.0) for the recipe.";
136
307
  function createAgentShieldMiddleware(_config = {}) {
137
308
  throw new Error(MIGRATION_ERROR);
@@ -397,7 +568,7 @@ function safeHostname(url) {
397
568
  // src/responses/agent-instruction.ts
398
569
  var MCP_I_DOCS_URL = "https://docs.knowthat.ai/mcp-i/getting-started";
399
570
  var DEFAULT_CONNECT_PATH = "/connect";
400
- function buildAgentInstructionResponse(request, decision, redirectUrl) {
571
+ function buildAgentInstructionResponse(request, decision, redirectUrl, options) {
401
572
  const resolved = resolveUrl(redirectUrl ?? DEFAULT_CONNECT_PATH, request.url);
402
573
  const agentName = decision.agentName || decision.agentType || "unknown";
403
574
  if (!resolved.searchParams.has("agent")) {
@@ -448,8 +619,11 @@ It only takes a moment and you won't need to do it again. Once you're done, ask
448
619
  confidence: decision.confidence
449
620
  }
450
621
  };
451
- const response = server.NextResponse.json(body, { status: 401 });
452
- response.headers.set("WWW-Authenticate", `KYA realm="api", authorization_uri="${authUrl}"`);
622
+ const bodyReadable200 = options?.bodyReadable200 ?? false;
623
+ const response = server.NextResponse.json(body, { status: bodyReadable200 ? 200 : 401 });
624
+ if (!bodyReadable200) {
625
+ response.headers.set("WWW-Authenticate", `KYA realm="api", authorization_uri="${authUrl}"`);
626
+ }
453
627
  response.headers.set(
454
628
  "Link",
455
629
  `<${authUrl}>; rel="kya-authorize", <${MCP_I_DOCS_URL}>; rel="help"`
@@ -642,7 +816,14 @@ function withCheckpointApi(config = {}) {
642
816
  return buildRedirectResponse(request, decision, config);
643
817
  }
644
818
  const targetUrl = config.redirectUrl || decision.redirectUrl;
645
- return buildAgentInstructionResponse(request, decision, targetUrl);
819
+ const bodyReadable200 = checkpointShared.selectBodyReadable200(
820
+ config.delegationChallengeMode ?? "spec-401",
821
+ request.headers,
822
+ result.data.detection?.detectionClass
823
+ );
824
+ return buildAgentInstructionResponse(request, decision, targetUrl, {
825
+ bodyReadable200
826
+ });
646
827
  }
647
828
  case "challenge": {
648
829
  return buildRedirectResponse(request, decision, config);
@@ -1007,9 +1188,6 @@ async function applyPolicy(request, detection, config) {
1007
1188
  );
1008
1189
  }
1009
1190
  }
1010
-
1011
- // src/index.ts
1012
- var VERSION = "0.1.0";
1013
1191
  /**
1014
1192
  * @fileoverview Checkpoint Next.js Integration
1015
1193
  * @license MIT OR Apache-2.0
package/dist/index.mjs CHANGED
@@ -1,8 +1,10 @@
1
1
  import { verifyRequest, renderDecisionAsResponse } from '@kya-os/checkpoint-wasm-runtime/orchestrator';
2
2
  import { makeSystemClock, makePolicyEvaluator, makeReputationOracle, makeStatusListCache, makeDidResolver } from '@kya-os/checkpoint-wasm-runtime/adapters';
3
- import { NextResponse } from 'next/server';
4
- import { isKnownAiCrawler, createEvaluationContext, evaluatePolicy, ENFORCEMENT_ACTIONS, PolicyConfigSchema, DEFAULT_POLICY, matchPath, acceptsHtml, encodeVerdictCookie, classifyResponseShape, BLOCKED_PATH, createPolicyFetcher, VERDICT_COOKIE_NAME } from '@kya-os/checkpoint-shared';
3
+ import { makeDetectionReporter } from '@kya-os/checkpoint-wasm-runtime/reporter';
4
+ import { selectBodyReadable200, PolicyFetcher, isKnownAiCrawler, createEvaluationContext, evaluatePolicy, ENFORCEMENT_ACTIONS, PolicyConfigSchema, DEFAULT_POLICY, matchPath, requestCarriesDelegationProof, acceptsHtml, encodeVerdictCookie, classifyResponseShape, BLOCKED_PATH, createPolicyFetcher, VERDICT_COOKIE_NAME } from '@kya-os/checkpoint-shared';
5
5
  export { DEFAULT_POLICY, ENFORCEMENT_ACTIONS, createEvaluationContext, evaluatePolicy } from '@kya-os/checkpoint-shared';
6
+ import { NextResponse } from 'next/server';
7
+ import { makeComposedPolicyCache, evaluateComposedPolicy, verifyResultToAuthorizeInput } from '@kya-os/checkpoint-wasm-runtime/composed-policy';
6
8
 
7
9
  // src/middleware-node.ts
8
10
  function adaptToNextResponse(rendered, req) {
@@ -53,6 +55,96 @@ function applyHeaders(res, headers) {
53
55
  res.headers.set(key, value);
54
56
  }
55
57
  }
58
+ var DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
59
+ var NOOP_LOGGER = {
60
+ shadowDivergence: () => {
61
+ },
62
+ evaluationError: () => {
63
+ }
64
+ };
65
+ function makeComposedPolicyContext(opts) {
66
+ const { projectId, fetcher } = opts;
67
+ const cache = makeComposedPolicyCache({ compile: opts.compile, cacheMax: opts.cacheMax });
68
+ const logger = opts.logger ?? NOOP_LOGGER;
69
+ return {
70
+ async apply(result, path) {
71
+ const structured = { decision: result.decision, acted: false };
72
+ const policy = await fetcher.getPolicy(projectId);
73
+ const outcome = await evaluateComposedPolicy({
74
+ cache,
75
+ projectId,
76
+ flags: {
77
+ policyLanguage: policy.policyLanguage,
78
+ policySourceText: policy.policySourceText,
79
+ engineEnforcementEnabled: policy.engineEnforcementEnabled,
80
+ enabled: policy.enabled
81
+ },
82
+ authorizeInput: verifyResultToAuthorizeInput(result, { tenantId: projectId, path }),
83
+ baselineDecisionKind: result.decision.kind
84
+ });
85
+ if ((outcome.status === "acting" || outcome.status === "shadow") && outcome.diverged) {
86
+ logger.shadowDivergence({
87
+ projectId,
88
+ path,
89
+ engineDecision: outcome.engineDecision.kind,
90
+ structuredDecision: result.decision.kind,
91
+ detectionClass: result.detectionDetail.detectionClass.type,
92
+ verificationMethod: result.detectionDetail.verificationMethod,
93
+ confidence: result.detectionDetail.confidence,
94
+ agentName: result.detectionDetail.detectedAgent?.name
95
+ });
96
+ }
97
+ if (outcome.status === "error") {
98
+ logger.evaluationError(projectId, outcome.error);
99
+ return structured;
100
+ }
101
+ if (outcome.status === "acting") {
102
+ return {
103
+ decision: outcome.engineDecision,
104
+ acted: true,
105
+ // Echo the SSOT revision pin with the decision it produced (#3246
106
+ // PR5). Conditional spread: absent upstream stays absent here.
107
+ ...policy.policySourceHash ? { composedBlobHash: policy.policySourceHash } : {}
108
+ };
109
+ }
110
+ return structured;
111
+ },
112
+ async trustedDelegationRoots() {
113
+ const policy = await fetcher.getPolicy(projectId);
114
+ return policy.trustedDelegationRoots ?? [];
115
+ }
116
+ };
117
+ }
118
+ async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
119
+ if (!resolver) return void 0;
120
+ if (!requestCarriesDelegationProof(headers)) return void 0;
121
+ const roots = await resolver();
122
+ return roots.length > 0 ? roots : void 0;
123
+ }
124
+ async function applyComposedPolicy(context, result, path) {
125
+ if (!context) return;
126
+ try {
127
+ const outcome = await context.apply(result, path);
128
+ if (outcome.acted) {
129
+ result.decision = outcome.decision;
130
+ if (outcome.composedBlobHash) {
131
+ result.composedBlobHash = outcome.composedBlobHash;
132
+ }
133
+ }
134
+ } catch {
135
+ }
136
+ }
137
+ var consoleComposedPolicyLogger = {
138
+ shadowDivergence(info) {
139
+ console.warn("[checkpoint/composed-policy] shadow-divergence", info);
140
+ },
141
+ evaluationError(projectId, error) {
142
+ console.error(
143
+ `[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
144
+ error
145
+ );
146
+ }
147
+ };
56
148
 
57
149
  // src/translate.ts
58
150
  async function nextRequestToHttpLike(req, opts = {}) {
@@ -97,15 +189,96 @@ function extractRemoteAddress(req) {
97
189
  // src/middleware-node.ts
98
190
  function withCheckpoint(config) {
99
191
  const opts = buildVerifyOpts(config);
192
+ const reporter = buildReporter(config);
193
+ const composed = buildComposedContext(config);
194
+ const trustedRootsResolver = buildTrustedRootsResolver(config, composed);
100
195
  const translateOpts = { drainJsonBody: config.drainJsonBody };
101
- return async function checkpointMiddleware(req) {
196
+ return async function checkpointMiddleware(req, event) {
102
197
  const httpLike = await nextRequestToHttpLike(req, translateOpts);
103
- const result = await verifyRequest(httpLike, opts);
198
+ const trustedDelegationRoots = await resolveTrustedDelegationRootsForRequest(
199
+ trustedRootsResolver,
200
+ req.headers
201
+ );
202
+ const result = await verifyRequest(
203
+ httpLike,
204
+ trustedDelegationRoots ? { ...opts, trustedDelegationRoots } : opts
205
+ );
206
+ await applyComposedPolicy(composed, result, req.nextUrl.pathname);
207
+ if (reporter) {
208
+ const reportPromise = reporter(result, extractReporterContext(req));
209
+ if (event) {
210
+ event.waitUntil(reportPromise);
211
+ }
212
+ }
104
213
  await dispatchOnResult(config, result, req);
105
- const rendered = renderDecisionAsResponse(result);
214
+ const bodyReadable200 = selectBodyReadable200(
215
+ config.delegationChallengeMode ?? "spec-401",
216
+ req.headers,
217
+ result.detectionDetail.detectionClass
218
+ );
219
+ const rendered = renderDecisionAsResponse(result, { bodyReadable200 });
106
220
  return adaptToNextResponse(rendered, req);
107
221
  };
108
222
  }
223
+ var SDK_NAME = "@kya-os/checkpoint-nextjs";
224
+ var VERSION = "1.7.1";
225
+ function buildReporter(config, runtime = "node") {
226
+ if (!config.apiKey) return null;
227
+ return makeDetectionReporter({
228
+ apiKey: config.apiKey,
229
+ baseUrl: config.baseUrl,
230
+ debug: config.debug,
231
+ // Self-identify (incl. node-vs-edge) so the dashboard can version-gate
232
+ // enforcement. Next.js EDGE composed enforcement is opt-in (needs
233
+ // `cedarWasmModule`), so the dashboard shows it as opt-in, never "Enforcing".
234
+ sdk: { name: SDK_NAME, version: VERSION, runtime }
235
+ });
236
+ }
237
+ function buildTrustedRootsResolver(config, composed) {
238
+ if (composed?.trustedDelegationRoots) {
239
+ return () => composed.trustedDelegationRoots();
240
+ }
241
+ if (!config.projectId) return null;
242
+ const fetcher = new PolicyFetcher({
243
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
244
+ apiKey: config.apiKey,
245
+ cacheTtlSeconds: config.policyCacheTtlSeconds
246
+ });
247
+ const projectId = config.projectId;
248
+ return async () => (await fetcher.getPolicy(projectId)).trustedDelegationRoots ?? [];
249
+ }
250
+ function buildComposedContext(config) {
251
+ if (config.composedPolicyEnforcer) return config.composedPolicyEnforcer;
252
+ if (!config.projectId) return null;
253
+ return makeComposedPolicyContext({
254
+ projectId: config.projectId,
255
+ fetcher: new PolicyFetcher({
256
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
257
+ apiKey: config.apiKey,
258
+ cacheTtlSeconds: config.policyCacheTtlSeconds
259
+ }),
260
+ // LAZY dynamic import — NOT a top-level `import` — so the node-only
261
+ // `./policy` glue (`createRequire`/`fs` at module load) is never pulled into
262
+ // the Edge bundle. `middleware-edge.ts` imports helpers from this file, so a
263
+ // top-level `./policy` import would surface as a side-effect import in the
264
+ // edge bundle and boot-fail on Vercel edge. The import is cached after first
265
+ // call; the core's single-flight cache wraps the (now async) compile.
266
+ compile: async (_language, source) => {
267
+ const { createPolicyEvaluator } = await import('@kya-os/checkpoint-wasm-runtime/policy');
268
+ return createPolicyEvaluator(source);
269
+ },
270
+ logger: config.debug ? consoleComposedPolicyLogger : void 0
271
+ });
272
+ }
273
+ function extractReporterContext(req) {
274
+ return {
275
+ userAgent: req.headers.get("user-agent") ?? void 0,
276
+ ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0,
277
+ path: req.nextUrl.pathname,
278
+ url: req.nextUrl.href,
279
+ method: req.method
280
+ };
281
+ }
109
282
  function buildVerifyOpts(config) {
110
283
  const overrides = config.adapters ?? {};
111
284
  return {
@@ -129,8 +302,6 @@ async function dispatchOnResult(config, result, req) {
129
302
  } catch {
130
303
  }
131
304
  }
132
-
133
- // src/middleware.ts
134
305
  var MIGRATION_ERROR = "@kya-os/checkpoint-nextjs's `createAgentShieldMiddleware` / `agentShield` were deleted in Phase D (engine consolidation). The 600-line TS pattern matcher that backed them is gone. Migrate to `withCheckpoint` from `@kya-os/checkpoint-nextjs` (Node runtime) or `@kya-os/checkpoint-nextjs/edge` (Edge runtime). See packages/checkpoint-nextjs/CHANGELOG.md (1.0.0) for the recipe.";
135
306
  function createAgentShieldMiddleware(_config = {}) {
136
307
  throw new Error(MIGRATION_ERROR);
@@ -396,7 +567,7 @@ function safeHostname(url) {
396
567
  // src/responses/agent-instruction.ts
397
568
  var MCP_I_DOCS_URL = "https://docs.knowthat.ai/mcp-i/getting-started";
398
569
  var DEFAULT_CONNECT_PATH = "/connect";
399
- function buildAgentInstructionResponse(request, decision, redirectUrl) {
570
+ function buildAgentInstructionResponse(request, decision, redirectUrl, options) {
400
571
  const resolved = resolveUrl(redirectUrl ?? DEFAULT_CONNECT_PATH, request.url);
401
572
  const agentName = decision.agentName || decision.agentType || "unknown";
402
573
  if (!resolved.searchParams.has("agent")) {
@@ -447,8 +618,11 @@ It only takes a moment and you won't need to do it again. Once you're done, ask
447
618
  confidence: decision.confidence
448
619
  }
449
620
  };
450
- const response = NextResponse.json(body, { status: 401 });
451
- response.headers.set("WWW-Authenticate", `KYA realm="api", authorization_uri="${authUrl}"`);
621
+ const bodyReadable200 = options?.bodyReadable200 ?? false;
622
+ const response = NextResponse.json(body, { status: bodyReadable200 ? 200 : 401 });
623
+ if (!bodyReadable200) {
624
+ response.headers.set("WWW-Authenticate", `KYA realm="api", authorization_uri="${authUrl}"`);
625
+ }
452
626
  response.headers.set(
453
627
  "Link",
454
628
  `<${authUrl}>; rel="kya-authorize", <${MCP_I_DOCS_URL}>; rel="help"`
@@ -641,7 +815,14 @@ function withCheckpointApi(config = {}) {
641
815
  return buildRedirectResponse(request, decision, config);
642
816
  }
643
817
  const targetUrl = config.redirectUrl || decision.redirectUrl;
644
- return buildAgentInstructionResponse(request, decision, targetUrl);
818
+ const bodyReadable200 = selectBodyReadable200(
819
+ config.delegationChallengeMode ?? "spec-401",
820
+ request.headers,
821
+ result.data.detection?.detectionClass
822
+ );
823
+ return buildAgentInstructionResponse(request, decision, targetUrl, {
824
+ bodyReadable200
825
+ });
645
826
  }
646
827
  case "challenge": {
647
828
  return buildRedirectResponse(request, decision, config);
@@ -1006,9 +1187,6 @@ async function applyPolicy(request, detection, config) {
1006
1187
  );
1007
1188
  }
1008
1189
  }
1009
-
1010
- // src/index.ts
1011
- var VERSION = "0.1.0";
1012
1190
  /**
1013
1191
  * @fileoverview Checkpoint Next.js Integration
1014
1192
  * @license MIT OR Apache-2.0
@@ -1,8 +1,12 @@
1
- import { NextRequest, NextResponse } from 'next/server';
1
+ import { NextRequest, NextFetchEvent, NextResponse } from 'next/server';
2
2
  export { initEngineEdge } from '@kya-os/checkpoint-wasm-runtime/orchestrator/edge';
3
- import { CheckpointConfig } from './middleware-node.mjs';
3
+ export { initPolicyEvaluatorEdge } from '@kya-os/checkpoint-wasm-runtime/policy-edge';
4
+ import { C as CheckpointConfig } from './config-DAwIA4DB.mjs';
4
5
  import '@kya-os/checkpoint-wasm-runtime/adapters';
5
6
  import '@kya-os/checkpoint-wasm-runtime/engine';
7
+ import '@kya-os/checkpoint-shared';
8
+ import './composed-policy.mjs';
9
+ import '@kya-os/checkpoint-wasm-runtime/composed-policy';
6
10
 
7
11
  /**
8
12
  * D.3 — Edge-runtime Next.js middleware entry.
@@ -41,6 +45,6 @@ import '@kya-os/checkpoint-wasm-runtime/engine';
41
45
  * factory closure is being built. The first request awaits the same
42
46
  * promise; subsequent requests resolve sync.
43
47
  */
44
- declare function withCheckpoint(config: CheckpointConfig): (req: NextRequest) => Promise<NextResponse>;
48
+ declare function withCheckpoint(config: CheckpointConfig): (req: NextRequest, event?: NextFetchEvent) => Promise<NextResponse>;
45
49
 
46
50
  export { CheckpointConfig, withCheckpoint };
@@ -1,8 +1,12 @@
1
- import { NextRequest, NextResponse } from 'next/server';
1
+ import { NextRequest, NextFetchEvent, NextResponse } from 'next/server';
2
2
  export { initEngineEdge } from '@kya-os/checkpoint-wasm-runtime/orchestrator/edge';
3
- import { CheckpointConfig } from './middleware-node.js';
3
+ export { initPolicyEvaluatorEdge } from '@kya-os/checkpoint-wasm-runtime/policy-edge';
4
+ import { C as CheckpointConfig } from './config-DyU4l5er.js';
4
5
  import '@kya-os/checkpoint-wasm-runtime/adapters';
5
6
  import '@kya-os/checkpoint-wasm-runtime/engine';
7
+ import '@kya-os/checkpoint-shared';
8
+ import './composed-policy.js';
9
+ import '@kya-os/checkpoint-wasm-runtime/composed-policy';
6
10
 
7
11
  /**
8
12
  * D.3 — Edge-runtime Next.js middleware entry.
@@ -41,6 +45,6 @@ import '@kya-os/checkpoint-wasm-runtime/engine';
41
45
  * factory closure is being built. The first request awaits the same
42
46
  * promise; subsequent requests resolve sync.
43
47
  */
44
- declare function withCheckpoint(config: CheckpointConfig): (req: NextRequest) => Promise<NextResponse>;
48
+ declare function withCheckpoint(config: CheckpointConfig): (req: NextRequest, event?: NextFetchEvent) => Promise<NextResponse>;
45
49
 
46
50
  export { CheckpointConfig, withCheckpoint };