@kya-os/checkpoint-nextjs 1.1.4 → 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 (43) hide show
  1. package/CHANGELOG.md +190 -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 +162 -9
  17. package/dist/index.mjs +163 -10
  18. package/dist/middleware-edge.d.mts +7 -3
  19. package/dist/middleware-edge.d.ts +7 -3
  20. package/dist/middleware-edge.js +159 -4
  21. package/dist/middleware-edge.mjs +156 -4
  22. package/dist/middleware-node.d.mts +39 -101
  23. package/dist/middleware-node.d.ts +39 -101
  24. package/dist/middleware-node.js +166 -4
  25. package/dist/middleware-node.mjs +163 -5
  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 +8 -11
  39. package/dist/wasm-middleware.d.mts +0 -98
  40. package/dist/wasm-middleware.d.ts +0 -98
  41. package/dist/wasm-middleware.js +0 -125
  42. package/dist/wasm-middleware.mjs +0 -121
  43. package/templates/middleware-wasm-100.ts +0 -161
package/CHANGELOG.md CHANGED
@@ -1,5 +1,195 @@
1
1
  # @kya-os/checkpoint-nextjs
2
2
 
3
+ ## 1.6.0 — Self-report SDK identity + runtime (version-gating)
4
+
5
+ **Minor release — additive + a fix.** `withCheckpoint`'s detection reporter now
6
+ self-reports `sdk: { name: '@kya-os/checkpoint-nextjs', version, runtime }` —
7
+ with `runtime: 'node' | 'edge'` distinguishing the two entries — so the dashboard
8
+ can version-gate "composed policy enforces here" on the actual installed SDK,
9
+ and correctly show the **edge** runtime as opt-in (composed enforcement there
10
+ needs `cedarWasmModule`, which detections can't observe) rather than falsely
11
+ "Enforcing" (the @Policy version-gating work, #3076).
12
+
13
+ ### Fixed
14
+
15
+ - **`VERSION` was stale (`0.1.0`)** — long drifted from `package.json`. It is now
16
+ single-sourced (re-exported from `middleware-node`) and pinned to
17
+ `package.json` by a unit test, so it can't drift again. This matters because
18
+ `VERSION` is now the SDK version the reporter self-reports for gating; the old
19
+ `0.1.0` would have failed the gate for every install.
20
+
21
+ ## 1.5.0 — Composed-policy (kya-os-engine) enforcement
22
+
23
+ **Minor release — additive.** Makes a customer's `/policy-compose` output enforce
24
+ IN-PROCESS via the shared composed-policy core
25
+ (`@kya-os/checkpoint-wasm-runtime/composed-policy`), byte-for-byte the same as
26
+ the DNS Gateway and `@kya-os/checkpoint-express@1.5.0` (engine = the detection +
27
+ enforcement SSOT). Without the new `projectId` config the middleware behaves
28
+ exactly as 1.4.0 (detection + structured policy only).
29
+
30
+ ### Added
31
+
32
+ - **`projectId`** on `CheckpointConfig` — opt into composed-policy enforcement.
33
+ The project's policy is fetched from
34
+ `<dashboardUrl ?? baseUrl ?? default>/api/internal/policies/${projectId}`; when
35
+ it carries a deployed Cedar bundle with `engineEnforcementEnabled` on, the
36
+ engine decision is enforced in-process.
37
+ - **Shadow-first**: deployed-but-not-enforcing computes + logs divergence
38
+ (gated on `debug`) without acting.
39
+ - **Fail-open**: any compile/evaluation/fetch fault keeps the structured
40
+ decision — a policy fault never 5xxs.
41
+ - **Empty-Cedar guard**: blank source never reaches the evaluator.
42
+ - **`composedPolicyEnforcer`** — advanced/testing seam to inject a pre-built
43
+ composed-policy context.
44
+ - **`cedarWasmModule`** (Edge only) — the statically-imported cedar-web
45
+ `WebAssembly.Module` that enables composed enforcement under the Edge runtime.
46
+
47
+ ### Node vs Edge
48
+
49
+ - **Node runtime (`./node`)** — composed enforcement is **default-on** (sync
50
+ `createPolicyEvaluator`; cedar loads lazily, never bundled to edge).
51
+ - **Edge runtime (`./edge`)** — **consumer-opt-in**: the seam stays inert unless
52
+ the host wires `cedarWasmModule`:
53
+
54
+ ```ts
55
+ import cedarWasmModule from '@kya-os/checkpoint-wasm-runtime/wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm?module';
56
+ export default withCheckpoint({ projectId, cedarWasmModule });
57
+ // next.config: experiments.asyncWebAssembly + a .wasm asset rule
58
+ ```
59
+
60
+ The ~2 MB cedar binary is deliberately NOT forced into every consumer's Edge
61
+ Middleware bundle (Vercel's plan-dependent size cap). Edge composed
62
+ enforcement is unproven on Vercel/webpack edge in-repo; flipping it to
63
+ default-on is gated on a real edge deploy measurement (follow-up). Until then,
64
+ edge without `cedarWasmModule` behaves exactly as 1.4.0.
65
+
66
+ ### Cross-runtime parity
67
+
68
+ Built on the shared core, so the `VerifyResult → AuthorizeInput` projection
69
+ (category map, verified-delegation allowlist, the `mcp_i_handshake`
70
+ optimistic-detail override), the empty-Cedar guard, the compile cache, and the
71
+ act-gate are identical across the DNS Gateway, Express, and Next.js. The composed
72
+ seam runs BEFORE the detection reporter so the dashboard records the enforced
73
+ decision (matching Express). Path comes from `req.nextUrl.pathname` (query-free,
74
+ what verification saw); fetch base honors `dashboardUrl ?? baseUrl`.
75
+
76
+ ## 1.4.0 — 2026-05-26 — Detection reporter on `withCheckpoint` (closes latent bug)
77
+
78
+ **Minor release.** Closes the same architectural gap as
79
+ `@kya-os/checkpoint-express@1.4.0` — `withCheckpoint` (both Node and
80
+ Edge variants) verified locally via WASM but had no path to ship
81
+ detections back to the dashboard. The setup flow currently generates
82
+ `withAgentShield` snippets (legacy `api-middleware.ts`, which has its
83
+ own reporter), so this gap was latent in nextjs. Closing it now
84
+ prevents the same silent-onboarding failure when customers migrate to
85
+ the documented canonical API.
86
+
87
+ ### Added
88
+
89
+ - **`apiKey`** on `CheckpointConfig` — wires the shared reporter from
90
+ `@kya-os/checkpoint-wasm-runtime/reporter`. Mirrors the express
91
+ config exactly. Resolve from `process.env.CHECKPOINT_API_KEY`.
92
+ - **`baseUrl`** — override the dashboard host. Default
93
+ `https://kya.vouched.id`.
94
+ - **`debug`** — surface reporter failures via `console.warn`. Default
95
+ `false`.
96
+
97
+ Both `middleware-node.ts` and `middleware-edge.ts` wire the reporter
98
+ from the same `_buildReporter` + `_extractReporterContext` seams, so
99
+ Node and Edge runtimes ship byte-equivalent payloads to
100
+ `/api/v1/log-detection`.
101
+
102
+ ## 1.3.0 — 2026-05-18
103
+
104
+ **Minor release with BREAKING removals.** Closes the deprecation cycle
105
+ opened in 1.1.2 via PR #2610 / AgentDetector-Deletion-1. Per project
106
+ semver policy this is shipped as a minor bump (not a major) because:
107
+ (a) the deprecation landed yesterday and was effectively one calendar
108
+ day, (b) the package is pre-Adobe-trial with no external pins to
109
+ `^1.x.0`, and (c) the workspace-wide deletion-gate test pins the absence
110
+ structurally so re-introduction is mechanically blocked.
111
+
112
+ ### BREAKING — removals
113
+
114
+ - **`useAgentDetection` hook removed** (`src/hooks.ts`). Wrapped the
115
+ legacy `AgentDetector` class that has now been removed from
116
+ `@kya-os/checkpoint@1.1.0`. **Migration path:** use `withCheckpoint`
117
+ from `@kya-os/checkpoint-nextjs` for server-side middleware
118
+ (engine-backed, returns canonical envelopes) or import
119
+ `KNOWN_AGENT_PATTERNS` directly from `@kya-os/checkpoint-shared` for
120
+ rare client-side pattern matching.
121
+ - **`createWasmAgentShieldMiddleware` factory removed** along with the
122
+ whole `src/wasm-middleware.ts` file. It internally constructed a
123
+ legacy `AgentDetector` and never actually used the WASM instance for
124
+ detection (the `wasmInstance` arg only bumped confidence by 15%).
125
+ **Migration path:** `withCheckpoint` from `@kya-os/checkpoint-nextjs`
126
+ — engine-backed, runs the full orchestrator including envelope
127
+ verification.
128
+ - **`./wasm-middleware` subpath export removed** from `package.json`
129
+ `exports`. Imports of
130
+ `@kya-os/checkpoint-nextjs/wasm-middleware` will fail to resolve.
131
+ - **`instantiateWasm` helper removed** (was co-located in
132
+ `wasm-middleware.ts`). It was a one-line `WebAssembly.instantiate`
133
+ wrapper; customers loading WASM manually can call the Web API
134
+ directly. With `withCheckpoint`, manual WASM loading is no longer
135
+ needed at all — `@kya-os/checkpoint-wasm-runtime`'s loaders handle
136
+ resolution under Node and Edge runtimes.
137
+ - **`useDetectionMonitor` continues to be exported** — it accepts any
138
+ `DetectionResult` and never depended on `AgentDetector`. Reusable
139
+ with engine-backed detection results.
140
+ - **`middleware-wasm-100.ts` template removed** — the canonical starter
141
+ template is now `withCheckpoint` (see `README.md` and the templates
142
+ under `templates/` that already cover Node + Edge runtimes).
143
+
144
+ ### Removed tests
145
+
146
+ - `src/__tests__/hooks.test.ts` — covered `useAgentDetection`
147
+ including the deprecation-warning regression test added in #2610.
148
+ - `src/__tests__/wasm-middleware.test.ts` — covered
149
+ `createWasmAgentShieldMiddleware` including the deprecation-warning
150
+ regression test added in #2610.
151
+
152
+ ### Build config
153
+
154
+ - `tsup.config.ts` entry list no longer references `src/wasm-middleware.ts`.
155
+
156
+ ### Coordination
157
+
158
+ Ships alongside `@kya-os/checkpoint@1.1.0` (defining package — removes
159
+ the `AgentDetector` class). No engine-surface change; cross-runtime
160
+ parity gate is unaffected.
161
+
162
+ ## 1.2.0 — 2026-05-18
163
+
164
+ **Minor release** — peer to `@kya-os/checkpoint-wasm-runtime@1.4.0`.
165
+ Bundler-port docs + E2E gate + Monitor-default visibility.
166
+
167
+ ### Changed
168
+
169
+ - QUICKSTART rewritten with **Bundler compatibility** + **Webpack
170
+ fallback** sections. The `--target bundler` artifact works under
171
+ Next.js 15+ Turbopack, Next.js 14 `next dev --turbo`, Vite, and
172
+ esbuild bundling mode out of the box. Webpack 5 + `asyncWebAssembly`
173
+ is documented as **incompatible** with `--target bundler`
174
+ (wasm-bindgen's sync `.wasm` import receives a Promise instead of
175
+ the resolved module — exports table breaks). Recommended Webpack
176
+ path is the `./engine/node` (or `./orchestrator/node`) safety net.
177
+
178
+ ### Added
179
+
180
+ - `tests-e2e/nextjs-consumer/` fixture + matching CI workflow
181
+ (`.github/workflows/e2e-nextjs-bundler.yml`) exercising the
182
+ `./engine/node` safety net under both Turbopack (`next dev --turbo`)
183
+ and Webpack (`next build` + `next start`).
184
+ - Tier-3 Monitor-default visibility: a default-config `withCheckpoint`
185
+ install no longer blocks ChatGPT-User et al. unless the consumer
186
+ writes a tenant-policy rule or opts into
187
+ `tier3_action: 'block'`. See
188
+ [wasm-runtime@1.4.0 CHANGELOG](../checkpoint-wasm-runtime/CHANGELOG.md)
189
+ for the migration story.
190
+
191
+ ---
192
+
3
193
  ## 1.1.4 — 2026-05-18
4
194
 
5
195
  Companion patch for `@kya-os/checkpoint-wasm-runtime@1.2.0`.
@@ -0,0 +1,108 @@
1
+ import { ComposedPolicyCompile } from '@kya-os/checkpoint-wasm-runtime/composed-policy';
2
+ import { Decision, VerifyResult } from '@kya-os/checkpoint-wasm-runtime/engine';
3
+ import { PolicyFetcher } from '@kya-os/checkpoint-shared';
4
+
5
+ /**
6
+ * Composed-policy (kya-os-engine) wiring for the Next.js middleware.
7
+ *
8
+ * A THIN layer on top of the shared core
9
+ * (`@kya-os/checkpoint-wasm-runtime/composed-policy`): the core owns all the
10
+ * logic (empty-Cedar deny-all guard, compile-once LRU cache, act-gate,
11
+ * divergence, and the `verifyResultToAuthorizeInput` parity projection), so this
12
+ * module only fetches the project's `PolicyConfig`, drives the core once per
13
+ * request, maps the tagged outcome to a decision-swap signal, and logs
14
+ * (debug-gated). Runtime-neutral — the caller injects the compiler:
15
+ * - Node: `(language, source) => createPolicyEvaluator(source)` (`./policy`)
16
+ * - Edge: `(language, source) => evaluatePolicy(language, source)` (`./policy-edge`)
17
+ *
18
+ * This is the SDK sibling of `@kya-os/checkpoint-express`'s composed-policy
19
+ * wiring; both consume the same core so the DNS Gateway, Express, and Next.js
20
+ * produce the same decision for the same composed Cedar bundle.
21
+ */
22
+
23
+ /** Dashboard the composed-policy fetch defaults to when no base URL is set. */
24
+ declare const DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
25
+ /**
26
+ * Telemetry sink. The shadow-divergence signal is the go/no-go instrument for
27
+ * flipping a project to ENFORCE. Defaults to a no-op so the SDK never logs
28
+ * unprompted — `withCheckpoint({ debug: true })` wires the console logger.
29
+ */
30
+ interface ComposedPolicyLogger {
31
+ shadowDivergence(info: ShadowDivergenceInfo): void;
32
+ evaluationError(projectId: string, error: unknown): void;
33
+ }
34
+ interface ShadowDivergenceInfo {
35
+ projectId: string;
36
+ path?: string;
37
+ engineDecision: Decision['kind'];
38
+ structuredDecision: Decision['kind'];
39
+ detectionClass: string;
40
+ verificationMethod?: string;
41
+ confidence: number;
42
+ agentName?: string;
43
+ }
44
+ /** Result of one composed-policy evaluation: the decision to enforce + whether it replaced the baseline. */
45
+ interface ComposedPolicyApplyResult {
46
+ decision: Decision;
47
+ acted: boolean;
48
+ }
49
+ interface ComposedPolicyContext {
50
+ /**
51
+ * Evaluate the project's composed policy for one request. Reads
52
+ * `result.decision` as the structured baseline for the divergence comparison;
53
+ * the caller applies `acted ? decision` afterwards. Never throws.
54
+ */
55
+ apply(result: VerifyResult, path: string | undefined): Promise<ComposedPolicyApplyResult>;
56
+ /**
57
+ * Resolve the org's trusted Layer-2 delegation root DIDs from the project's
58
+ * policy payload (P2 / DR-1). The middleware forwards these into the engine's
59
+ * `ContextSpec.trustedDelegationRoots` on delegation requests. Optional so an
60
+ * injected `composedPolicyEnforcer` (advanced/testing) need not implement it —
61
+ * absence ⇒ no roots ⇒ the engine's open default. Never throws (a fetch fault
62
+ * resolves to `[]`).
63
+ */
64
+ trustedDelegationRoots?(): Promise<string[]>;
65
+ }
66
+ interface MakeComposedPolicyContextOptions {
67
+ projectId: string;
68
+ /** Fetches the project's `PolicyConfig` (carries the composed-policy fields). */
69
+ fetcher: PolicyFetcher;
70
+ /** Target compiler — Node `createPolicyEvaluator`-backed or edge `evaluatePolicy`. */
71
+ compile: ComposedPolicyCompile;
72
+ logger?: ComposedPolicyLogger;
73
+ cacheMax?: number;
74
+ }
75
+ declare function makeComposedPolicyContext(opts: MakeComposedPolicyContextOptions): ComposedPolicyContext;
76
+ /**
77
+ * Resolves the org's trusted delegation roots (empty when none). Built per
78
+ * middleware factory from whatever source can supply them — the composed
79
+ * context's accessor, or (when no context exists, e.g. Edge without
80
+ * `cedarWasmModule`) a `projectId`-only policy fetch.
81
+ */
82
+ type TrustedDelegationRootsResolver = () => Promise<string[]>;
83
+ /**
84
+ * Resolve the org trusted-delegation roots to inject into the engine for THIS
85
+ * request (P2 / DR-1). Returns `undefined` — leaving `VerifyRequestOpts`
86
+ * byte-identical to pre-P2 — unless (a) a resolver is configured and (b) the
87
+ * request actually carries a delegation-proof header (so the human /
88
+ * no-delegation hot path never pays the early policy fetch). Shared by the Node
89
+ * and Edge middleware entries.
90
+ */
91
+ declare function resolveTrustedDelegationRootsForRequest(resolver: TrustedDelegationRootsResolver | null, headers: Headers): Promise<string[] | undefined>;
92
+ /**
93
+ * The per-request seam shared by both middleware entries. Evaluates the composed
94
+ * policy and swaps `result.decision` IN PLACE when the engine acts — so the
95
+ * swap happens BEFORE the detection reporter fires and before
96
+ * `renderDecisionAsResponse`, exactly like the Express runtime (the reporter
97
+ * records the enforced decision). Fail-OPEN: any fault keeps the structured
98
+ * decision; a policy fault never breaks the response.
99
+ */
100
+ declare function applyComposedPolicy(context: ComposedPolicyContext | null, result: VerifyResult, path: string | undefined): Promise<void>;
101
+ /**
102
+ * Debug logger mirroring the worker's `console.warn`/`console.error` shadow +
103
+ * fail-open telemetry. Wired by `withCheckpoint` only when `config.debug` is
104
+ * set, so the default SDK posture stays silent.
105
+ */
106
+ declare const consoleComposedPolicyLogger: ComposedPolicyLogger;
107
+
108
+ export { type ComposedPolicyApplyResult, type ComposedPolicyContext, type ComposedPolicyLogger, DEFAULT_DASHBOARD_URL, type MakeComposedPolicyContextOptions, type ShadowDivergenceInfo, type TrustedDelegationRootsResolver, applyComposedPolicy, consoleComposedPolicyLogger, makeComposedPolicyContext, resolveTrustedDelegationRootsForRequest };
@@ -0,0 +1,108 @@
1
+ import { ComposedPolicyCompile } from '@kya-os/checkpoint-wasm-runtime/composed-policy';
2
+ import { Decision, VerifyResult } from '@kya-os/checkpoint-wasm-runtime/engine';
3
+ import { PolicyFetcher } from '@kya-os/checkpoint-shared';
4
+
5
+ /**
6
+ * Composed-policy (kya-os-engine) wiring for the Next.js middleware.
7
+ *
8
+ * A THIN layer on top of the shared core
9
+ * (`@kya-os/checkpoint-wasm-runtime/composed-policy`): the core owns all the
10
+ * logic (empty-Cedar deny-all guard, compile-once LRU cache, act-gate,
11
+ * divergence, and the `verifyResultToAuthorizeInput` parity projection), so this
12
+ * module only fetches the project's `PolicyConfig`, drives the core once per
13
+ * request, maps the tagged outcome to a decision-swap signal, and logs
14
+ * (debug-gated). Runtime-neutral — the caller injects the compiler:
15
+ * - Node: `(language, source) => createPolicyEvaluator(source)` (`./policy`)
16
+ * - Edge: `(language, source) => evaluatePolicy(language, source)` (`./policy-edge`)
17
+ *
18
+ * This is the SDK sibling of `@kya-os/checkpoint-express`'s composed-policy
19
+ * wiring; both consume the same core so the DNS Gateway, Express, and Next.js
20
+ * produce the same decision for the same composed Cedar bundle.
21
+ */
22
+
23
+ /** Dashboard the composed-policy fetch defaults to when no base URL is set. */
24
+ declare const DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
25
+ /**
26
+ * Telemetry sink. The shadow-divergence signal is the go/no-go instrument for
27
+ * flipping a project to ENFORCE. Defaults to a no-op so the SDK never logs
28
+ * unprompted — `withCheckpoint({ debug: true })` wires the console logger.
29
+ */
30
+ interface ComposedPolicyLogger {
31
+ shadowDivergence(info: ShadowDivergenceInfo): void;
32
+ evaluationError(projectId: string, error: unknown): void;
33
+ }
34
+ interface ShadowDivergenceInfo {
35
+ projectId: string;
36
+ path?: string;
37
+ engineDecision: Decision['kind'];
38
+ structuredDecision: Decision['kind'];
39
+ detectionClass: string;
40
+ verificationMethod?: string;
41
+ confidence: number;
42
+ agentName?: string;
43
+ }
44
+ /** Result of one composed-policy evaluation: the decision to enforce + whether it replaced the baseline. */
45
+ interface ComposedPolicyApplyResult {
46
+ decision: Decision;
47
+ acted: boolean;
48
+ }
49
+ interface ComposedPolicyContext {
50
+ /**
51
+ * Evaluate the project's composed policy for one request. Reads
52
+ * `result.decision` as the structured baseline for the divergence comparison;
53
+ * the caller applies `acted ? decision` afterwards. Never throws.
54
+ */
55
+ apply(result: VerifyResult, path: string | undefined): Promise<ComposedPolicyApplyResult>;
56
+ /**
57
+ * Resolve the org's trusted Layer-2 delegation root DIDs from the project's
58
+ * policy payload (P2 / DR-1). The middleware forwards these into the engine's
59
+ * `ContextSpec.trustedDelegationRoots` on delegation requests. Optional so an
60
+ * injected `composedPolicyEnforcer` (advanced/testing) need not implement it —
61
+ * absence ⇒ no roots ⇒ the engine's open default. Never throws (a fetch fault
62
+ * resolves to `[]`).
63
+ */
64
+ trustedDelegationRoots?(): Promise<string[]>;
65
+ }
66
+ interface MakeComposedPolicyContextOptions {
67
+ projectId: string;
68
+ /** Fetches the project's `PolicyConfig` (carries the composed-policy fields). */
69
+ fetcher: PolicyFetcher;
70
+ /** Target compiler — Node `createPolicyEvaluator`-backed or edge `evaluatePolicy`. */
71
+ compile: ComposedPolicyCompile;
72
+ logger?: ComposedPolicyLogger;
73
+ cacheMax?: number;
74
+ }
75
+ declare function makeComposedPolicyContext(opts: MakeComposedPolicyContextOptions): ComposedPolicyContext;
76
+ /**
77
+ * Resolves the org's trusted delegation roots (empty when none). Built per
78
+ * middleware factory from whatever source can supply them — the composed
79
+ * context's accessor, or (when no context exists, e.g. Edge without
80
+ * `cedarWasmModule`) a `projectId`-only policy fetch.
81
+ */
82
+ type TrustedDelegationRootsResolver = () => Promise<string[]>;
83
+ /**
84
+ * Resolve the org trusted-delegation roots to inject into the engine for THIS
85
+ * request (P2 / DR-1). Returns `undefined` — leaving `VerifyRequestOpts`
86
+ * byte-identical to pre-P2 — unless (a) a resolver is configured and (b) the
87
+ * request actually carries a delegation-proof header (so the human /
88
+ * no-delegation hot path never pays the early policy fetch). Shared by the Node
89
+ * and Edge middleware entries.
90
+ */
91
+ declare function resolveTrustedDelegationRootsForRequest(resolver: TrustedDelegationRootsResolver | null, headers: Headers): Promise<string[] | undefined>;
92
+ /**
93
+ * The per-request seam shared by both middleware entries. Evaluates the composed
94
+ * policy and swaps `result.decision` IN PLACE when the engine acts — so the
95
+ * swap happens BEFORE the detection reporter fires and before
96
+ * `renderDecisionAsResponse`, exactly like the Express runtime (the reporter
97
+ * records the enforced decision). Fail-OPEN: any fault keeps the structured
98
+ * decision; a policy fault never breaks the response.
99
+ */
100
+ declare function applyComposedPolicy(context: ComposedPolicyContext | null, result: VerifyResult, path: string | undefined): Promise<void>;
101
+ /**
102
+ * Debug logger mirroring the worker's `console.warn`/`console.error` shadow +
103
+ * fail-open telemetry. Wired by `withCheckpoint` only when `config.debug` is
104
+ * set, so the default SDK posture stays silent.
105
+ */
106
+ declare const consoleComposedPolicyLogger: ComposedPolicyLogger;
107
+
108
+ export { type ComposedPolicyApplyResult, type ComposedPolicyContext, type ComposedPolicyLogger, DEFAULT_DASHBOARD_URL, type MakeComposedPolicyContextOptions, type ShadowDivergenceInfo, type TrustedDelegationRootsResolver, applyComposedPolicy, consoleComposedPolicyLogger, makeComposedPolicyContext, resolveTrustedDelegationRootsForRequest };
@@ -0,0 +1,91 @@
1
+ 'use strict';
2
+
3
+ var composedPolicy = require('@kya-os/checkpoint-wasm-runtime/composed-policy');
4
+ var checkpointShared = require('@kya-os/checkpoint-shared');
5
+
6
+ // src/composed-policy.ts
7
+ var DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
8
+ var NOOP_LOGGER = {
9
+ shadowDivergence: () => {
10
+ },
11
+ evaluationError: () => {
12
+ }
13
+ };
14
+ function makeComposedPolicyContext(opts) {
15
+ const { projectId, fetcher } = opts;
16
+ const cache = composedPolicy.makeComposedPolicyCache({ compile: opts.compile, cacheMax: opts.cacheMax });
17
+ const logger = opts.logger ?? NOOP_LOGGER;
18
+ return {
19
+ async apply(result, path) {
20
+ const structured = { decision: result.decision, acted: false };
21
+ const policy = await fetcher.getPolicy(projectId);
22
+ const outcome = await composedPolicy.evaluateComposedPolicy({
23
+ cache,
24
+ projectId,
25
+ flags: {
26
+ policyLanguage: policy.policyLanguage,
27
+ policySourceText: policy.policySourceText,
28
+ engineEnforcementEnabled: policy.engineEnforcementEnabled,
29
+ enabled: policy.enabled
30
+ },
31
+ authorizeInput: composedPolicy.verifyResultToAuthorizeInput(result, { tenantId: projectId, path }),
32
+ baselineDecisionKind: result.decision.kind
33
+ });
34
+ if ((outcome.status === "acting" || outcome.status === "shadow") && outcome.diverged) {
35
+ logger.shadowDivergence({
36
+ projectId,
37
+ path,
38
+ engineDecision: outcome.engineDecision.kind,
39
+ structuredDecision: result.decision.kind,
40
+ detectionClass: result.detectionDetail.detectionClass.type,
41
+ verificationMethod: result.detectionDetail.verificationMethod,
42
+ confidence: result.detectionDetail.confidence,
43
+ agentName: result.detectionDetail.detectedAgent?.name
44
+ });
45
+ }
46
+ if (outcome.status === "error") {
47
+ logger.evaluationError(projectId, outcome.error);
48
+ return structured;
49
+ }
50
+ if (outcome.status === "acting") {
51
+ return { decision: outcome.engineDecision, acted: true };
52
+ }
53
+ return structured;
54
+ },
55
+ async trustedDelegationRoots() {
56
+ const policy = await fetcher.getPolicy(projectId);
57
+ return policy.trustedDelegationRoots ?? [];
58
+ }
59
+ };
60
+ }
61
+ async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
62
+ if (!resolver) return void 0;
63
+ if (!checkpointShared.requestCarriesDelegationProof(headers)) return void 0;
64
+ const roots = await resolver();
65
+ return roots.length > 0 ? roots : void 0;
66
+ }
67
+ async function applyComposedPolicy(context, result, path) {
68
+ if (!context) return;
69
+ try {
70
+ const outcome = await context.apply(result, path);
71
+ if (outcome.acted) result.decision = outcome.decision;
72
+ } catch {
73
+ }
74
+ }
75
+ var consoleComposedPolicyLogger = {
76
+ shadowDivergence(info) {
77
+ console.warn("[checkpoint/composed-policy] shadow-divergence", info);
78
+ },
79
+ evaluationError(projectId, error) {
80
+ console.error(
81
+ `[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
82
+ error
83
+ );
84
+ }
85
+ };
86
+
87
+ exports.DEFAULT_DASHBOARD_URL = DEFAULT_DASHBOARD_URL;
88
+ exports.applyComposedPolicy = applyComposedPolicy;
89
+ exports.consoleComposedPolicyLogger = consoleComposedPolicyLogger;
90
+ exports.makeComposedPolicyContext = makeComposedPolicyContext;
91
+ exports.resolveTrustedDelegationRootsForRequest = resolveTrustedDelegationRootsForRequest;
@@ -0,0 +1,85 @@
1
+ import { makeComposedPolicyCache, evaluateComposedPolicy, verifyResultToAuthorizeInput } from '@kya-os/checkpoint-wasm-runtime/composed-policy';
2
+ import { requestCarriesDelegationProof } from '@kya-os/checkpoint-shared';
3
+
4
+ // src/composed-policy.ts
5
+ var DEFAULT_DASHBOARD_URL = "https://kya.vouched.id";
6
+ var NOOP_LOGGER = {
7
+ shadowDivergence: () => {
8
+ },
9
+ evaluationError: () => {
10
+ }
11
+ };
12
+ function makeComposedPolicyContext(opts) {
13
+ const { projectId, fetcher } = opts;
14
+ const cache = makeComposedPolicyCache({ compile: opts.compile, cacheMax: opts.cacheMax });
15
+ const logger = opts.logger ?? NOOP_LOGGER;
16
+ return {
17
+ async apply(result, path) {
18
+ const structured = { decision: result.decision, acted: false };
19
+ const policy = await fetcher.getPolicy(projectId);
20
+ const outcome = await evaluateComposedPolicy({
21
+ cache,
22
+ projectId,
23
+ flags: {
24
+ policyLanguage: policy.policyLanguage,
25
+ policySourceText: policy.policySourceText,
26
+ engineEnforcementEnabled: policy.engineEnforcementEnabled,
27
+ enabled: policy.enabled
28
+ },
29
+ authorizeInput: verifyResultToAuthorizeInput(result, { tenantId: projectId, path }),
30
+ baselineDecisionKind: result.decision.kind
31
+ });
32
+ if ((outcome.status === "acting" || outcome.status === "shadow") && outcome.diverged) {
33
+ logger.shadowDivergence({
34
+ projectId,
35
+ path,
36
+ engineDecision: outcome.engineDecision.kind,
37
+ structuredDecision: result.decision.kind,
38
+ detectionClass: result.detectionDetail.detectionClass.type,
39
+ verificationMethod: result.detectionDetail.verificationMethod,
40
+ confidence: result.detectionDetail.confidence,
41
+ agentName: result.detectionDetail.detectedAgent?.name
42
+ });
43
+ }
44
+ if (outcome.status === "error") {
45
+ logger.evaluationError(projectId, outcome.error);
46
+ return structured;
47
+ }
48
+ if (outcome.status === "acting") {
49
+ return { decision: outcome.engineDecision, acted: true };
50
+ }
51
+ return structured;
52
+ },
53
+ async trustedDelegationRoots() {
54
+ const policy = await fetcher.getPolicy(projectId);
55
+ return policy.trustedDelegationRoots ?? [];
56
+ }
57
+ };
58
+ }
59
+ async function resolveTrustedDelegationRootsForRequest(resolver, headers) {
60
+ if (!resolver) return void 0;
61
+ if (!requestCarriesDelegationProof(headers)) return void 0;
62
+ const roots = await resolver();
63
+ return roots.length > 0 ? roots : void 0;
64
+ }
65
+ async function applyComposedPolicy(context, result, path) {
66
+ if (!context) return;
67
+ try {
68
+ const outcome = await context.apply(result, path);
69
+ if (outcome.acted) result.decision = outcome.decision;
70
+ } catch {
71
+ }
72
+ }
73
+ var consoleComposedPolicyLogger = {
74
+ shadowDivergence(info) {
75
+ console.warn("[checkpoint/composed-policy] shadow-divergence", info);
76
+ },
77
+ evaluationError(projectId, error) {
78
+ console.error(
79
+ `[checkpoint/composed-policy] evaluation failed for ${projectId}; using structured decision:`,
80
+ error
81
+ );
82
+ }
83
+ };
84
+
85
+ export { DEFAULT_DASHBOARD_URL, applyComposedPolicy, consoleComposedPolicyLogger, makeComposedPolicyContext, resolveTrustedDelegationRootsForRequest };