@kya-os/checkpoint-nextjs 1.2.0 → 1.7.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.
Files changed (44) hide show
  1. package/CHANGELOG.md +159 -0
  2. package/dist/composed-policy.d.mts +108 -0
  3. package/dist/composed-policy.d.ts +108 -0
  4. package/dist/composed-policy.js +91 -0
  5. package/dist/composed-policy.mjs +85 -0
  6. package/dist/config-_nfPN3E3.d.mts +205 -0
  7. package/dist/config-kxFihzR_.d.ts +205 -0
  8. package/dist/create-middleware.js +0 -2
  9. package/dist/create-middleware.mjs +0 -2
  10. package/dist/edge-runtime-loader.js +3 -1
  11. package/dist/edge-runtime-loader.mjs +3 -1
  12. package/dist/edge-wasm-middleware.d.mts +6 -6
  13. package/dist/edge-wasm-middleware.d.ts +6 -6
  14. package/dist/index.d.mts +6 -14
  15. package/dist/index.d.ts +6 -14
  16. package/dist/index.js +160 -8
  17. package/dist/index.mjs +161 -9
  18. package/dist/middleware-edge.d.mts +7 -3
  19. package/dist/middleware-edge.d.ts +7 -3
  20. package/dist/middleware-edge.js +157 -3
  21. package/dist/middleware-edge.mjs +154 -3
  22. package/dist/middleware-node.d.mts +39 -116
  23. package/dist/middleware-node.d.ts +39 -116
  24. package/dist/middleware-node.js +164 -3
  25. package/dist/middleware-node.mjs +161 -4
  26. package/dist/middleware.d.mts +10 -1
  27. package/dist/middleware.d.ts +10 -1
  28. package/dist/middleware.js +6 -0
  29. package/dist/middleware.mjs +6 -1
  30. package/dist/nodejs-wasm-loader.d.mts +3 -4
  31. package/dist/nodejs-wasm-loader.d.ts +3 -4
  32. package/dist/nodejs-wasm-loader.js +1 -1
  33. package/dist/nodejs-wasm-loader.mjs +1 -1
  34. package/dist/signature-verifier.js +2 -2
  35. package/dist/signature-verifier.mjs +2 -2
  36. package/dist/wasm-setup.js +1 -1
  37. package/dist/wasm-setup.mjs +1 -1
  38. package/package.json +4 -9
  39. package/dist/.tsbuildinfo +0 -1
  40. package/dist/wasm-middleware.d.mts +0 -98
  41. package/dist/wasm-middleware.d.ts +0 -98
  42. package/dist/wasm-middleware.js +0 -125
  43. package/dist/wasm-middleware.mjs +0 -121
  44. package/templates/middleware-wasm-100.ts +0 -161
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,85 @@ 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 { decision: outcome.engineDecision, acted: true };
104
+ }
105
+ return structured;
106
+ },
107
+ async trustedDelegationRoots() {
108
+ const policy = await fetcher.getPolicy(projectId);
109
+ return policy.trustedDelegationRoots ?? [];
110
+ }
111
+ };
112
+ }
113
+ async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
114
+ if (!resolver) return void 0;
115
+ if (!checkpointShared.requestCarriesDelegationProof(headers)) return void 0;
116
+ const roots = await resolver();
117
+ return roots.length > 0 ? roots : void 0;
118
+ }
119
+ async function applyComposedPolicy(context, result, path) {
120
+ if (!context) return;
121
+ try {
122
+ const outcome = await context.apply(result, path);
123
+ if (outcome.acted) result.decision = outcome.decision;
124
+ } catch {
125
+ }
126
+ }
127
+ var consoleComposedPolicyLogger = {
128
+ shadowDivergence(info) {
129
+ console.warn("[checkpoint/composed-policy] shadow-divergence", info);
130
+ },
131
+ evaluationError(projectId, error) {
132
+ console.error(
133
+ `[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
134
+ error
135
+ );
136
+ }
137
+ };
57
138
 
58
139
  // src/translate.ts
59
140
  async function nextRequestToHttpLike(req, opts = {}) {
@@ -98,15 +179,91 @@ function extractRemoteAddress(req) {
98
179
  // src/middleware-node.ts
99
180
  function withCheckpoint(config) {
100
181
  const opts = buildVerifyOpts(config);
182
+ const reporter = buildReporter(config);
183
+ const composed = buildComposedContext(config);
184
+ const trustedRootsResolver = buildTrustedRootsResolver(config, composed);
101
185
  const translateOpts = { drainJsonBody: config.drainJsonBody };
102
- return async function checkpointMiddleware(req) {
186
+ return async function checkpointMiddleware(req, event) {
103
187
  const httpLike = await nextRequestToHttpLike(req, translateOpts);
104
- const result = await orchestrator.verifyRequest(httpLike, opts);
188
+ const trustedDelegationRoots = await resolveTrustedDelegationRootsForRequest(
189
+ trustedRootsResolver,
190
+ req.headers
191
+ );
192
+ const result = await orchestrator.verifyRequest(
193
+ httpLike,
194
+ trustedDelegationRoots ? { ...opts, trustedDelegationRoots } : opts
195
+ );
196
+ await applyComposedPolicy(composed, result, req.nextUrl.pathname);
197
+ if (reporter) {
198
+ const reportPromise = reporter(result, extractReporterContext(req));
199
+ if (event) {
200
+ event.waitUntil(reportPromise);
201
+ }
202
+ }
105
203
  await dispatchOnResult(config, result, req);
106
204
  const rendered = orchestrator.renderDecisionAsResponse(result);
107
205
  return adaptToNextResponse(rendered, req);
108
206
  };
109
207
  }
208
+ var SDK_NAME = "@kya-os/checkpoint-nextjs";
209
+ var VERSION = "1.7.0";
210
+ function buildReporter(config, runtime = "node") {
211
+ if (!config.apiKey) return null;
212
+ return reporter.makeDetectionReporter({
213
+ apiKey: config.apiKey,
214
+ baseUrl: config.baseUrl,
215
+ debug: config.debug,
216
+ // Self-identify (incl. node-vs-edge) so the dashboard can version-gate
217
+ // enforcement. Next.js EDGE composed enforcement is opt-in (needs
218
+ // `cedarWasmModule`), so the dashboard shows it as opt-in, never "Enforcing".
219
+ sdk: { name: SDK_NAME, version: VERSION, runtime }
220
+ });
221
+ }
222
+ function buildTrustedRootsResolver(config, composed) {
223
+ if (composed?.trustedDelegationRoots) {
224
+ return () => composed.trustedDelegationRoots();
225
+ }
226
+ if (!config.projectId) return null;
227
+ const fetcher = new checkpointShared.PolicyFetcher({
228
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
229
+ apiKey: config.apiKey,
230
+ cacheTtlSeconds: config.policyCacheTtlSeconds
231
+ });
232
+ const projectId = config.projectId;
233
+ return async () => (await fetcher.getPolicy(projectId)).trustedDelegationRoots ?? [];
234
+ }
235
+ function buildComposedContext(config) {
236
+ if (config.composedPolicyEnforcer) return config.composedPolicyEnforcer;
237
+ if (!config.projectId) return null;
238
+ return makeComposedPolicyContext({
239
+ projectId: config.projectId,
240
+ fetcher: new checkpointShared.PolicyFetcher({
241
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
242
+ apiKey: config.apiKey,
243
+ cacheTtlSeconds: config.policyCacheTtlSeconds
244
+ }),
245
+ // LAZY dynamic import — NOT a top-level `import` — so the node-only
246
+ // `./policy` glue (`createRequire`/`fs` at module load) is never pulled into
247
+ // the Edge bundle. `middleware-edge.ts` imports helpers from this file, so a
248
+ // top-level `./policy` import would surface as a side-effect import in the
249
+ // edge bundle and boot-fail on Vercel edge. The import is cached after first
250
+ // call; the core's single-flight cache wraps the (now async) compile.
251
+ compile: async (_language, source) => {
252
+ const { createPolicyEvaluator } = await import('@kya-os/checkpoint-wasm-runtime/policy');
253
+ return createPolicyEvaluator(source);
254
+ },
255
+ logger: config.debug ? consoleComposedPolicyLogger : void 0
256
+ });
257
+ }
258
+ function extractReporterContext(req) {
259
+ return {
260
+ userAgent: req.headers.get("user-agent") ?? void 0,
261
+ ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0,
262
+ path: req.nextUrl.pathname,
263
+ url: req.nextUrl.href,
264
+ method: req.method
265
+ };
266
+ }
110
267
  function buildVerifyOpts(config) {
111
268
  const overrides = config.adapters ?? {};
112
269
  return {
@@ -130,8 +287,6 @@ async function dispatchOnResult(config, result, req) {
130
287
  } catch {
131
288
  }
132
289
  }
133
-
134
- // src/middleware.ts
135
290
  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
291
  function createAgentShieldMiddleware(_config = {}) {
137
292
  throw new Error(MIGRATION_ERROR);
@@ -1007,9 +1162,6 @@ async function applyPolicy(request, detection, config) {
1007
1162
  );
1008
1163
  }
1009
1164
  }
1010
-
1011
- // src/index.ts
1012
- var VERSION = "0.1.0";
1013
1165
  /**
1014
1166
  * @fileoverview Checkpoint Next.js Integration
1015
1167
  * @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 { 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,85 @@ 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 { decision: outcome.engineDecision, acted: true };
103
+ }
104
+ return structured;
105
+ },
106
+ async trustedDelegationRoots() {
107
+ const policy = await fetcher.getPolicy(projectId);
108
+ return policy.trustedDelegationRoots ?? [];
109
+ }
110
+ };
111
+ }
112
+ async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
113
+ if (!resolver) return void 0;
114
+ if (!requestCarriesDelegationProof(headers)) return void 0;
115
+ const roots = await resolver();
116
+ return roots.length > 0 ? roots : void 0;
117
+ }
118
+ async function applyComposedPolicy(context, result, path) {
119
+ if (!context) return;
120
+ try {
121
+ const outcome = await context.apply(result, path);
122
+ if (outcome.acted) result.decision = outcome.decision;
123
+ } catch {
124
+ }
125
+ }
126
+ var consoleComposedPolicyLogger = {
127
+ shadowDivergence(info) {
128
+ console.warn("[checkpoint/composed-policy] shadow-divergence", info);
129
+ },
130
+ evaluationError(projectId, error) {
131
+ console.error(
132
+ `[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
133
+ error
134
+ );
135
+ }
136
+ };
56
137
 
57
138
  // src/translate.ts
58
139
  async function nextRequestToHttpLike(req, opts = {}) {
@@ -97,15 +178,91 @@ function extractRemoteAddress(req) {
97
178
  // src/middleware-node.ts
98
179
  function withCheckpoint(config) {
99
180
  const opts = buildVerifyOpts(config);
181
+ const reporter = buildReporter(config);
182
+ const composed = buildComposedContext(config);
183
+ const trustedRootsResolver = buildTrustedRootsResolver(config, composed);
100
184
  const translateOpts = { drainJsonBody: config.drainJsonBody };
101
- return async function checkpointMiddleware(req) {
185
+ return async function checkpointMiddleware(req, event) {
102
186
  const httpLike = await nextRequestToHttpLike(req, translateOpts);
103
- const result = await verifyRequest(httpLike, opts);
187
+ const trustedDelegationRoots = await resolveTrustedDelegationRootsForRequest(
188
+ trustedRootsResolver,
189
+ req.headers
190
+ );
191
+ const result = await verifyRequest(
192
+ httpLike,
193
+ trustedDelegationRoots ? { ...opts, trustedDelegationRoots } : opts
194
+ );
195
+ await applyComposedPolicy(composed, result, req.nextUrl.pathname);
196
+ if (reporter) {
197
+ const reportPromise = reporter(result, extractReporterContext(req));
198
+ if (event) {
199
+ event.waitUntil(reportPromise);
200
+ }
201
+ }
104
202
  await dispatchOnResult(config, result, req);
105
203
  const rendered = renderDecisionAsResponse(result);
106
204
  return adaptToNextResponse(rendered, req);
107
205
  };
108
206
  }
207
+ var SDK_NAME = "@kya-os/checkpoint-nextjs";
208
+ var VERSION = "1.7.0";
209
+ function buildReporter(config, runtime = "node") {
210
+ if (!config.apiKey) return null;
211
+ return makeDetectionReporter({
212
+ apiKey: config.apiKey,
213
+ baseUrl: config.baseUrl,
214
+ debug: config.debug,
215
+ // Self-identify (incl. node-vs-edge) so the dashboard can version-gate
216
+ // enforcement. Next.js EDGE composed enforcement is opt-in (needs
217
+ // `cedarWasmModule`), so the dashboard shows it as opt-in, never "Enforcing".
218
+ sdk: { name: SDK_NAME, version: VERSION, runtime }
219
+ });
220
+ }
221
+ function buildTrustedRootsResolver(config, composed) {
222
+ if (composed?.trustedDelegationRoots) {
223
+ return () => composed.trustedDelegationRoots();
224
+ }
225
+ if (!config.projectId) return null;
226
+ const fetcher = new PolicyFetcher({
227
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
228
+ apiKey: config.apiKey,
229
+ cacheTtlSeconds: config.policyCacheTtlSeconds
230
+ });
231
+ const projectId = config.projectId;
232
+ return async () => (await fetcher.getPolicy(projectId)).trustedDelegationRoots ?? [];
233
+ }
234
+ function buildComposedContext(config) {
235
+ if (config.composedPolicyEnforcer) return config.composedPolicyEnforcer;
236
+ if (!config.projectId) return null;
237
+ return makeComposedPolicyContext({
238
+ projectId: config.projectId,
239
+ fetcher: new PolicyFetcher({
240
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
241
+ apiKey: config.apiKey,
242
+ cacheTtlSeconds: config.policyCacheTtlSeconds
243
+ }),
244
+ // LAZY dynamic import — NOT a top-level `import` — so the node-only
245
+ // `./policy` glue (`createRequire`/`fs` at module load) is never pulled into
246
+ // the Edge bundle. `middleware-edge.ts` imports helpers from this file, so a
247
+ // top-level `./policy` import would surface as a side-effect import in the
248
+ // edge bundle and boot-fail on Vercel edge. The import is cached after first
249
+ // call; the core's single-flight cache wraps the (now async) compile.
250
+ compile: async (_language, source) => {
251
+ const { createPolicyEvaluator } = await import('@kya-os/checkpoint-wasm-runtime/policy');
252
+ return createPolicyEvaluator(source);
253
+ },
254
+ logger: config.debug ? consoleComposedPolicyLogger : void 0
255
+ });
256
+ }
257
+ function extractReporterContext(req) {
258
+ return {
259
+ userAgent: req.headers.get("user-agent") ?? void 0,
260
+ ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0,
261
+ path: req.nextUrl.pathname,
262
+ url: req.nextUrl.href,
263
+ method: req.method
264
+ };
265
+ }
109
266
  function buildVerifyOpts(config) {
110
267
  const overrides = config.adapters ?? {};
111
268
  return {
@@ -129,8 +286,6 @@ async function dispatchOnResult(config, result, req) {
129
286
  } catch {
130
287
  }
131
288
  }
132
-
133
- // src/middleware.ts
134
289
  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
290
  function createAgentShieldMiddleware(_config = {}) {
136
291
  throw new Error(MIGRATION_ERROR);
@@ -1006,9 +1161,6 @@ async function applyPolicy(request, detection, config) {
1006
1161
  );
1007
1162
  }
1008
1163
  }
1009
-
1010
- // src/index.ts
1011
- var VERSION = "0.1.0";
1012
1164
  /**
1013
1165
  * @fileoverview Checkpoint Next.js Integration
1014
1166
  * @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-_nfPN3E3.mjs';
4
5
  import '@kya-os/checkpoint-wasm-runtime/adapters';
5
6
  import '@kya-os/checkpoint-wasm-runtime/engine';
7
+ import './composed-policy.mjs';
8
+ import '@kya-os/checkpoint-wasm-runtime/composed-policy';
9
+ import '@kya-os/checkpoint-shared';
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-kxFihzR_.js';
4
5
  import '@kya-os/checkpoint-wasm-runtime/adapters';
5
6
  import '@kya-os/checkpoint-wasm-runtime/engine';
7
+ import './composed-policy.js';
8
+ import '@kya-os/checkpoint-wasm-runtime/composed-policy';
9
+ import '@kya-os/checkpoint-shared';
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,10 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var edge = require('@kya-os/checkpoint-wasm-runtime/orchestrator/edge');
4
- var server = require('next/server');
4
+ var policyEdge = require('@kya-os/checkpoint-wasm-runtime/policy-edge');
5
5
  var checkpointShared = require('@kya-os/checkpoint-shared');
6
+ var server = require('next/server');
7
+ var composedPolicy = require('@kya-os/checkpoint-wasm-runtime/composed-policy');
6
8
  require('@kya-os/checkpoint-wasm-runtime/orchestrator');
7
9
  var adapters = require('@kya-os/checkpoint-wasm-runtime/adapters');
10
+ var reporter = require('@kya-os/checkpoint-wasm-runtime/reporter');
8
11
 
9
12
  // src/middleware-edge.ts
10
13
  function adaptToNextResponse(rendered, req) {
@@ -55,6 +58,85 @@ function applyHeaders(res, headers) {
55
58
  res.headers.set(key, value);
56
59
  }
57
60
  }
61
+ var DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
62
+ var NOOP_LOGGER = {
63
+ shadowDivergence: () => {
64
+ },
65
+ evaluationError: () => {
66
+ }
67
+ };
68
+ function makeComposedPolicyContext(opts) {
69
+ const { projectId, fetcher } = opts;
70
+ const cache = composedPolicy.makeComposedPolicyCache({ compile: opts.compile, cacheMax: opts.cacheMax });
71
+ const logger = opts.logger ?? NOOP_LOGGER;
72
+ return {
73
+ async apply(result, path) {
74
+ const structured = { decision: result.decision, acted: false };
75
+ const policy = await fetcher.getPolicy(projectId);
76
+ const outcome = await composedPolicy.evaluateComposedPolicy({
77
+ cache,
78
+ projectId,
79
+ flags: {
80
+ policyLanguage: policy.policyLanguage,
81
+ policySourceText: policy.policySourceText,
82
+ engineEnforcementEnabled: policy.engineEnforcementEnabled,
83
+ enabled: policy.enabled
84
+ },
85
+ authorizeInput: composedPolicy.verifyResultToAuthorizeInput(result, { tenantId: projectId, path }),
86
+ baselineDecisionKind: result.decision.kind
87
+ });
88
+ if ((outcome.status === "acting" || outcome.status === "shadow") && outcome.diverged) {
89
+ logger.shadowDivergence({
90
+ projectId,
91
+ path,
92
+ engineDecision: outcome.engineDecision.kind,
93
+ structuredDecision: result.decision.kind,
94
+ detectionClass: result.detectionDetail.detectionClass.type,
95
+ verificationMethod: result.detectionDetail.verificationMethod,
96
+ confidence: result.detectionDetail.confidence,
97
+ agentName: result.detectionDetail.detectedAgent?.name
98
+ });
99
+ }
100
+ if (outcome.status === "error") {
101
+ logger.evaluationError(projectId, outcome.error);
102
+ return structured;
103
+ }
104
+ if (outcome.status === "acting") {
105
+ return { decision: outcome.engineDecision, acted: true };
106
+ }
107
+ return structured;
108
+ },
109
+ async trustedDelegationRoots() {
110
+ const policy = await fetcher.getPolicy(projectId);
111
+ return policy.trustedDelegationRoots ?? [];
112
+ }
113
+ };
114
+ }
115
+ async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
116
+ if (!resolver) return void 0;
117
+ if (!checkpointShared.requestCarriesDelegationProof(headers)) return void 0;
118
+ const roots = await resolver();
119
+ return roots.length > 0 ? roots : void 0;
120
+ }
121
+ async function applyComposedPolicy(context, result, path) {
122
+ if (!context) return;
123
+ try {
124
+ const outcome = await context.apply(result, path);
125
+ if (outcome.acted) result.decision = outcome.decision;
126
+ } catch {
127
+ }
128
+ }
129
+ var consoleComposedPolicyLogger = {
130
+ shadowDivergence(info) {
131
+ console.warn("[checkpoint/composed-policy] shadow-divergence", info);
132
+ },
133
+ evaluationError(projectId, error) {
134
+ console.error(
135
+ `[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
136
+ error
137
+ );
138
+ }
139
+ };
58
140
 
59
141
  // src/translate.ts
60
142
  async function nextRequestToHttpLike(req, opts = {}) {
@@ -97,6 +179,42 @@ function extractRemoteAddress(req) {
97
179
  }
98
180
 
99
181
  // src/middleware-node.ts
182
+ var SDK_NAME = "@kya-os/checkpoint-nextjs";
183
+ var VERSION = "1.7.0";
184
+ function buildReporter(config, runtime = "node") {
185
+ if (!config.apiKey) return null;
186
+ return reporter.makeDetectionReporter({
187
+ apiKey: config.apiKey,
188
+ baseUrl: config.baseUrl,
189
+ debug: config.debug,
190
+ // Self-identify (incl. node-vs-edge) so the dashboard can version-gate
191
+ // enforcement. Next.js EDGE composed enforcement is opt-in (needs
192
+ // `cedarWasmModule`), so the dashboard shows it as opt-in, never "Enforcing".
193
+ sdk: { name: SDK_NAME, version: VERSION, runtime }
194
+ });
195
+ }
196
+ function buildTrustedRootsResolver(config, composed) {
197
+ if (composed?.trustedDelegationRoots) {
198
+ return () => composed.trustedDelegationRoots();
199
+ }
200
+ if (!config.projectId) return null;
201
+ const fetcher = new checkpointShared.PolicyFetcher({
202
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
203
+ apiKey: config.apiKey,
204
+ cacheTtlSeconds: config.policyCacheTtlSeconds
205
+ });
206
+ const projectId = config.projectId;
207
+ return async () => (await fetcher.getPolicy(projectId)).trustedDelegationRoots ?? [];
208
+ }
209
+ function extractReporterContext(req) {
210
+ return {
211
+ userAgent: req.headers.get("user-agent") ?? void 0,
212
+ ipAddress: req.headers.get("x-forwarded-for")?.split(",")[0]?.trim() ?? req.headers.get("x-real-ip") ?? void 0,
213
+ path: req.nextUrl.pathname,
214
+ url: req.nextUrl.href,
215
+ method: req.method
216
+ };
217
+ }
100
218
  function buildVerifyOpts(config) {
101
219
  const overrides = config.adapters ?? {};
102
220
  return {
@@ -118,10 +236,27 @@ function buildVerifyOpts(config) {
118
236
  function withCheckpoint(config) {
119
237
  void edge.initEngineEdge();
120
238
  const opts = buildVerifyOpts(config);
239
+ const reporter = buildReporter(config, "edge");
240
+ const composed = buildComposedContext(config);
241
+ const trustedRootsResolver = buildTrustedRootsResolver(config, composed);
121
242
  const translateOpts = { drainJsonBody: config.drainJsonBody };
122
- return async function checkpointMiddlewareEdge(req) {
243
+ return async function checkpointMiddlewareEdge(req, event) {
123
244
  const httpLike = await nextRequestToHttpLike(req, translateOpts);
124
- const result = await edge.verifyRequestEdge(httpLike, opts);
245
+ const trustedDelegationRoots = await resolveTrustedDelegationRootsForRequest(
246
+ trustedRootsResolver,
247
+ req.headers
248
+ );
249
+ const result = await edge.verifyRequestEdge(
250
+ httpLike,
251
+ trustedDelegationRoots ? { ...opts, trustedDelegationRoots } : opts
252
+ );
253
+ await applyComposedPolicy(composed, result, req.nextUrl.pathname);
254
+ if (reporter) {
255
+ const reportPromise = reporter(result, extractReporterContext(req));
256
+ if (event) {
257
+ event.waitUntil(reportPromise);
258
+ }
259
+ }
125
260
  await dispatchOnResult(config, result, req);
126
261
  const rendered = edge.renderDecisionAsResponse(result);
127
262
  return adaptToNextResponse(rendered, req);
@@ -134,9 +269,28 @@ async function dispatchOnResult(config, result, req) {
134
269
  } catch {
135
270
  }
136
271
  }
272
+ function buildComposedContext(config) {
273
+ if (config.composedPolicyEnforcer) return config.composedPolicyEnforcer;
274
+ if (!config.projectId || !config.cedarWasmModule) return null;
275
+ policyEdge.initPolicyEvaluatorEdge(config.cedarWasmModule);
276
+ return makeComposedPolicyContext({
277
+ projectId: config.projectId,
278
+ fetcher: new checkpointShared.PolicyFetcher({
279
+ apiBaseUrl: config.dashboardUrl ?? config.baseUrl ?? DEFAULT_DASHBOARD_URL,
280
+ apiKey: config.apiKey,
281
+ cacheTtlSeconds: config.policyCacheTtlSeconds
282
+ }),
283
+ compile: (language, source) => policyEdge.evaluatePolicy(language, source),
284
+ logger: config.debug ? consoleComposedPolicyLogger : void 0
285
+ });
286
+ }
137
287
 
138
288
  Object.defineProperty(exports, "initEngineEdge", {
139
289
  enumerable: true,
140
290
  get: function () { return edge.initEngineEdge; }
141
291
  });
292
+ Object.defineProperty(exports, "initPolicyEvaluatorEdge", {
293
+ enumerable: true,
294
+ get: function () { return policyEdge.initPolicyEvaluatorEdge; }
295
+ });
142
296
  exports.withCheckpoint = withCheckpoint;