@kya-os/checkpoint-wasm-runtime 1.5.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +215 -0
- package/dist/engine-edge.d.mts +52 -16
- package/dist/engine-edge.d.ts +52 -16
- package/dist/engine-edge.js +11 -4
- package/dist/engine-edge.mjs +11 -4
- package/dist/index.d.mts +118 -1
- package/dist/index.d.ts +118 -1
- package/dist/orchestrator-edge.js +46 -13
- package/dist/orchestrator-edge.mjs +46 -13
- package/dist/orchestrator-node.js +35 -9
- package/dist/orchestrator-node.mjs +35 -9
- package/dist/orchestrator.d.mts +52 -16
- package/dist/orchestrator.d.ts +52 -16
- package/dist/orchestrator.js +46 -13
- package/dist/orchestrator.mjs +46 -13
- package/dist/policy.d.mts +148 -0
- package/dist/policy.d.ts +148 -0
- package/dist/policy.js +52 -0
- package/dist/policy.mjs +53 -0
- package/dist/reporter.d.mts +102 -0
- package/dist/reporter.d.ts +102 -0
- package/dist/reporter.js +125 -0
- package/dist/reporter.mjs +122 -0
- package/package.json +15 -5
- package/wasm/kya-os-engine/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine/package.json +4 -2
- package/wasm/kya-os-engine-bundler/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-cedar/README.md +26 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine.d.ts +77 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine.js +636 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm.d.ts +11 -0
- package/wasm/kya-os-engine-cedar/package.json +29 -0
- package/wasm/kya-os-engine-cedar-web/README.md +26 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine.d.ts +117 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine.js +694 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm.d.ts +11 -0
- package/wasm/kya-os-engine-cedar-web/package.json +31 -0
- package/wasm/kya-os-engine-web/kya_os_engine_bg.wasm +0 -0
- package/wasm/kya-os-engine-web/package.json +5 -3
- package/wasm/agentshield_wasm.d.ts +0 -485
- package/wasm/agentshield_wasm.js +0 -1551
- package/wasm/agentshield_wasm_bg.wasm +0 -0
- package/wasm/agentshield_wasm_bg.wasm.d.ts +0 -97
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,220 @@
|
|
|
1
1
|
# @kya-os/checkpoint-wasm-runtime
|
|
2
2
|
|
|
3
|
+
## 1.6.0 — 2026-05-26 — `./reporter` subpath
|
|
4
|
+
|
|
5
|
+
**Minor release** — adds the detection reporter consumed by the
|
|
6
|
+
engine-backed host wrappers in `@kya-os/checkpoint-express@1.4.0` and
|
|
7
|
+
`@kya-os/checkpoint-nextjs@1.4.0`.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`./reporter` subpath** exports `makeDetectionReporter(config)` and
|
|
12
|
+
`buildLogDetectionPayload(result, ctx)`. The reporter is a
|
|
13
|
+
fire-and-forget POST to `${baseUrl}/api/v1/log-detection` (default
|
|
14
|
+
`https://kya.vouched.id`) with `Authorization: Bearer ${apiKey}`.
|
|
15
|
+
Maps the engine's `VerifyResult` into the dashboard's
|
|
16
|
+
`LogDetectionRequestSchema` (detection + context + source=middleware
|
|
17
|
+
- enforcement + engine). Errors are swallowed unless `debug: true`.
|
|
18
|
+
- Runtime-agnostic (uses global `fetch` + `AbortController`); works
|
|
19
|
+
under Node 18+ and the Edge runtime without polyfills.
|
|
20
|
+
|
|
21
|
+
### Why
|
|
22
|
+
|
|
23
|
+
The two engine-backed host wrappers (`withCheckpoint` in express +
|
|
24
|
+
nextjs) ran verification locally via WASM but had no path to ship the
|
|
25
|
+
`VerifyResult` back to the dashboard. Customers installed the SDK,
|
|
26
|
+
deployed, and the onboarding "Verify connection" check failed forever
|
|
27
|
+
because the `detections` table never received a row. The reporter
|
|
28
|
+
closes that loop without re-introducing the legacy gateway round-trip.
|
|
29
|
+
|
|
30
|
+
## Unreleased — Phase-D.9b.1 — `initEngineEdge` switched to `--target bundler`
|
|
31
|
+
|
|
32
|
+
**Production-incident hotfix (2026-05-24).** `initEngineEdge()` previously
|
|
33
|
+
loaded the `wasm-pack --target web` artifact, which falls back to
|
|
34
|
+
`new URL('<wasm>', import.meta.url)` when no `moduleOrPath` is passed.
|
|
35
|
+
Cloudflare Workers don't materialise `import.meta.url` the way browsers do,
|
|
36
|
+
so the URL construction threw `TypeError: Invalid URL string` at engine
|
|
37
|
+
init — taking down the post-D.9b production gateway deploy twice in ~1h
|
|
38
|
+
(rolled back via `wrangler rollback` both times; captured in dev tail
|
|
39
|
+
run 26352287112).
|
|
40
|
+
|
|
41
|
+
Fix: switch `engine/edge.ts` to import the `--target bundler` artifact
|
|
42
|
+
(`@kya-os/checkpoint-wasm-runtime/wasm/kya-os-engine-bundler/kya_os_engine.js`).
|
|
43
|
+
The bundler target embeds the WASM inline via the host bundler's `.wasm`
|
|
44
|
+
import mechanism + initialises synchronously on module load. No URL
|
|
45
|
+
construction, no `import.meta.url` dependency, no `default()` init call.
|
|
46
|
+
|
|
47
|
+
### Behaviour change (no API surface change)
|
|
48
|
+
|
|
49
|
+
- `moduleOrPath` parameter is now reserved/ignored. The bundler target
|
|
50
|
+
loads the WASM at module-load time via the host bundler, so the
|
|
51
|
+
caller has no opportunity to inject a pre-fetched `WebAssembly.Module`.
|
|
52
|
+
Parameter retained in the signature for type-compat; the value is
|
|
53
|
+
intentionally unused.
|
|
54
|
+
- The `engine-edge.smoke.test.ts` "failed init recovery" regression
|
|
55
|
+
test was skipped (with a TODO for re-expressing the rejection-
|
|
56
|
+
caching guard via a dynamic-import mock) since the bundler target
|
|
57
|
+
can't be made to fail on caller input. The cache-clearing logic in
|
|
58
|
+
`ensureReady` is unchanged + still protects the same shape for OTHER
|
|
59
|
+
failure modes (e.g., dynamic import errors).
|
|
60
|
+
|
|
61
|
+
### Consumer compatibility
|
|
62
|
+
|
|
63
|
+
All known `initEngineEdge` consumers run inside a bundler that supports
|
|
64
|
+
`.wasm` imports — `@kya-os/gateway-worker` (wrangler), `@kya-os/checkpoint-
|
|
65
|
+
nextjs/middleware-edge` (webpack), `@kya-os/checkpoint-wasm-runtime/src/
|
|
66
|
+
engine/orchestrator/verify-request-edge` (consumed by both above). No
|
|
67
|
+
browser-direct consumer exists, so switching off the web target is safe.
|
|
68
|
+
|
|
69
|
+
### Version
|
|
70
|
+
|
|
71
|
+
Workspace-internal change; npm publish deferred until the next
|
|
72
|
+
coordinated cut. Workspace consumers (gateway worker, checkpoint-nextjs)
|
|
73
|
+
pick up the fix immediately via `pnpm` symlinks.
|
|
74
|
+
|
|
75
|
+
## Unreleased — Phase-D.9b — engine-only publish path
|
|
76
|
+
|
|
77
|
+
Internal-only change (no consumer-visible API removal). The
|
|
78
|
+
`rust/crates/agentshield-wasm` Rust crate was deleted as part of
|
|
79
|
+
Phase-D.9b after the Cloudflare gateway worker migrated onto
|
|
80
|
+
`./orchestrator/edge`. Build/publish plumbing follows:
|
|
81
|
+
|
|
82
|
+
- **Removed `copy-wasm` script** from `package.json`. The
|
|
83
|
+
`prepublishOnly` chain no longer copies the legacy
|
|
84
|
+
`agentshield_wasm_bg.wasm` artifact from the now-deleted crate —
|
|
85
|
+
publishing 1.4.4 against this tree would have failed at that step.
|
|
86
|
+
- **Removed `./wasm/agentshield_wasm_bg.wasm` subpath export.** The
|
|
87
|
+
legacy artifact is no longer shipped with the npm package.
|
|
88
|
+
- **Removed `wasm/agentshield_wasm*` files** from the package's `wasm/`
|
|
89
|
+
directory. Only the three `kya-os-engine*` artifact directories
|
|
90
|
+
(Node, web, bundler targets) remain.
|
|
91
|
+
|
|
92
|
+
### Orchestrator legacy header parser — compact-JWS shape accepted
|
|
93
|
+
|
|
94
|
+
`tryBuildMcpIFromLegacyHeader` (`engine/orchestrator/build-agent-request.ts`)
|
|
95
|
+
now accepts **two** wire shapes in the `KYA-Delegation` header when
|
|
96
|
+
`legacyEnvelopeFallback: true`:
|
|
97
|
+
|
|
98
|
+
1. JSON envelope `{"protected":"…","payload":"…","signature":"…"}`
|
|
99
|
+
(the pre-Envelope-1 TS bouncer form). Unchanged behavior.
|
|
100
|
+
2. Compact JWS `<protected>.<payload>.<signature>` (the form
|
|
101
|
+
consumed by the legacy `agentshield-wasm` `verify_mcp_i_proof`
|
|
102
|
+
function on the gateway worker). New in this release.
|
|
103
|
+
|
|
104
|
+
Why: the gateway-worker cutover in Phase-D.9b moves MCP-I parsing
|
|
105
|
+
from `verify_mcp_i_proof` (compact-JWS only) onto the orchestrator
|
|
106
|
+
(JSON-envelope only pre-this-release). Third-party agents or custom
|
|
107
|
+
integrations shipping compact JWS in the header would have silently
|
|
108
|
+
fallen through to PlainHttp post-cutover; this extension preserves
|
|
109
|
+
the parse path so they keep producing `McpI` agent requests.
|
|
110
|
+
|
|
111
|
+
JSON parse runs first because a compact JWS is never valid JSON.
|
|
112
|
+
A JSON object that's not envelope-shaped does NOT fall through to
|
|
113
|
+
the compact-JWS branch — it's unambiguously a malformed envelope
|
|
114
|
+
attempt, returns null. Coverage: 4 new fixtures in
|
|
115
|
+
`build-agent-request.test.ts` (19/19 pass).
|
|
116
|
+
|
|
117
|
+
The package's runtime API surface is unchanged. The legacy
|
|
118
|
+
`./edge` entry (`StaticWasmLoader`, `WasmDetector`,
|
|
119
|
+
`src/wasm-bindgen/agentshield_wasm.{js,d.ts}`) is still present in
|
|
120
|
+
source — its upstream consumers (`@kya-os/checkpoint-nextjs/edge`,
|
|
121
|
+
`@kya-os/checkpoint/wasm/loader-factory`) are throw-stubbed at the
|
|
122
|
+
public API layer, so the legacy WASM glue never executes at runtime.
|
|
123
|
+
A future cleanup will delete those source files; this release just
|
|
124
|
+
unblocks deleting the underlying Rust crate.
|
|
125
|
+
|
|
126
|
+
Phase-D.9b PR adds a structural deletion gate
|
|
127
|
+
(`packages/checkpoint-nextjs/src/__tests__/d9b-deletion-gate.test.ts`)
|
|
128
|
+
that re-asserts these conditions on every test run.
|
|
129
|
+
|
|
130
|
+
## 1.5.1 — 2026-05-20
|
|
131
|
+
|
|
132
|
+
**Tier 1 verification is now observable from the wire.** Closes the
|
|
133
|
+
diagnostic gap Bench-Detection-Delta V3 (2026-05-20) surfaced: although
|
|
134
|
+
Tier 1 RFC 9421 cryptographic verification was engaging correctly in
|
|
135
|
+
1.5.0, the response headers only exposed `Decision`-level info — operators
|
|
136
|
+
couldn't tell whether the engine had verified the request OR what tier
|
|
137
|
+
fired. Required a bench-side `onResult` callback to see
|
|
138
|
+
`detectionDetail.metadata.verified_*`. This patch surfaces the same
|
|
139
|
+
information on the wire.
|
|
140
|
+
|
|
141
|
+
Patch bump (not minor) because both changes are additive observability
|
|
142
|
+
improvements — no public API surface change, no behavior change for any
|
|
143
|
+
existing consumer:
|
|
144
|
+
|
|
145
|
+
| Change | Type | Consumer impact |
|
|
146
|
+
| ------------------------------------------------------------------------------------------------------ | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
147
|
+
| `X-Checkpoint-Verified-Tier` / `-Vendor` / `-Protocol` response headers | Additive | New headers only emitted when `detectionDetail.metadata.verified_*` populated. No existing consumer parsed these (they didn't exist). |
|
|
148
|
+
| `ruleset_hash` `t1:` slot now populates with vendor-keys SHA-256 (`t1:<64-hex>` instead of `t1:unset`) | Additive | The structured format documented `unset` / `disabled` / `<64-hex>` as valid slot values per [[Engine-Tier-Ruleset-Hash-1]]. Operators pinning on the literal `t1:unset` string would see breakage — but doing so was always against the documented contract (the slot was documented as a placeholder pending wiring). |
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
- **`X-Checkpoint-Verified-Tier` response header.** Emitted when
|
|
153
|
+
`detectionDetail.metadata.verified_tier` is a finite number or non-empty
|
|
154
|
+
string. Value is the stringified tier (`"1"` for Tier 1 RFC 9421 today;
|
|
155
|
+
`"2"` reserved for Tier 2 IP+UA cross-match attribution when that path
|
|
156
|
+
populates `verified_*`).
|
|
157
|
+
- **`X-Checkpoint-Verified-Vendor` response header.** Emitted when
|
|
158
|
+
`detectionDetail.metadata.verified_vendor` is a non-empty string.
|
|
159
|
+
Today: `openai` (the only Tier 1 vendor with a bundled JWK). Future
|
|
160
|
+
Anthropic / Google RFC 9421 signers will add `anthropic` / `google`
|
|
161
|
+
values without a SemVer event.
|
|
162
|
+
- **`X-Checkpoint-Verified-Protocol` response header.** Emitted when
|
|
163
|
+
`detectionDetail.metadata.verified_protocol` is a non-empty string.
|
|
164
|
+
Today: `rfc9421` (HTTP Message Signatures). Future MCP-I JWS envelope
|
|
165
|
+
verifications will emit `mcp-i` / `did-jws`.
|
|
166
|
+
- **`X-Checkpoint-Ruleset-Hash`'s `t1:` slot now populates.** Computed
|
|
167
|
+
at engine build time as SHA-256 of the canonical concat of every
|
|
168
|
+
`data/vendor-keys/*.json` file (sorted by filename, `\n--\n`
|
|
169
|
+
separator). Build-time panic gate on empty dir / empty file prevents
|
|
170
|
+
shipping a misleading empty-input hash (mirrors Tier 2/3 discipline).
|
|
171
|
+
The `cargo:rustc-env=KYA_OS_ENGINE_TIER1_KEYS_SHA256` producer in
|
|
172
|
+
`kya-os-engine/build.rs` is the single source of truth; `api.rs`
|
|
173
|
+
consumes via `env!()`.
|
|
174
|
+
|
|
175
|
+
### Defensive guards (PR #2718 reviewer feedback)
|
|
176
|
+
|
|
177
|
+
- `X-Checkpoint-Verified-Tier` number path uses `Number.isFinite` to
|
|
178
|
+
reject `NaN` / `±Infinity` (`typeof NaN === 'number'` is true in JS,
|
|
179
|
+
so a plain typeof check would emit `Verified-Tier: NaN`).
|
|
180
|
+
- `X-Checkpoint-Verified-Tier` string path requires `length > 0`
|
|
181
|
+
(mirrors `Verified-Vendor` / `Verified-Protocol` defensive guards).
|
|
182
|
+
|
|
183
|
+
### Tests
|
|
184
|
+
|
|
185
|
+
- New Rust drift gate `ruleset_hash_tier1_slot_resolves_to_vendor_keys_sha`
|
|
186
|
+
re-reads `data/vendor-keys/*.json` at test time + asserts the `t1:`
|
|
187
|
+
slot matches the computed SHA. Mirrors the existing Tier 2 YAML drift
|
|
188
|
+
gate. 96/96 lib tests pass.
|
|
189
|
+
- 6 new vitest cases on `render-decision.test.ts` cover the
|
|
190
|
+
`Verified-*` header emission (presence, absence, partial metadata,
|
|
191
|
+
Block-path co-emission, observe-mode co-emission, empty-string +
|
|
192
|
+
NaN + ±Infinity defensive guards, number-vs-string acceptance).
|
|
193
|
+
26/26 render-decision tests pass.
|
|
194
|
+
|
|
195
|
+
### What this DOESN'T change
|
|
196
|
+
|
|
197
|
+
- Engine verify-dispatch behavior — unchanged. Tier 1 was already
|
|
198
|
+
engaging in 1.5.0; this release only makes that visible.
|
|
199
|
+
- Public API surface — unchanged. No new exports, no new types, no
|
|
200
|
+
removed exports.
|
|
201
|
+
- Existing response headers — unchanged. `X-Checkpoint-Decision`,
|
|
202
|
+
`-Reason`, `-Engine`, `-Engine-Version` emit exactly as before.
|
|
203
|
+
- Ruleset-hash format — unchanged. The structured-prefix format
|
|
204
|
+
pinned by `ruleset_hash_matches_structured_per_tier_format` still
|
|
205
|
+
matches `sha256:t1:<slot>:t2:<slot>:t3:<slot>:t4:<slot>` where
|
|
206
|
+
each slot is one of `unset`/`disabled`/`[0-9a-f]{64}`. Only the
|
|
207
|
+
`t1:` slot's runtime value changed from `unset` to `<64-hex>`.
|
|
208
|
+
|
|
209
|
+
### Pin guidance
|
|
210
|
+
|
|
211
|
+
- Customers pinning `^1.5.0` (caret) → auto-pick up 1.5.1 on next
|
|
212
|
+
install. No action needed.
|
|
213
|
+
- Customers pinning `~1.5.0` (tilde) → auto-pick up 1.5.1 on next
|
|
214
|
+
install. No action needed.
|
|
215
|
+
- Customers pinning `1.5.0` (exact) → no auto-pickup. Bump to
|
|
216
|
+
`^1.5.1` to see Tier 1 attribution on the wire.
|
|
217
|
+
|
|
3
218
|
## 1.5.0 — 2026-05-19
|
|
4
219
|
|
|
5
220
|
**Formal announcement of HTTP-Sig-Verifier-1 — Tier 1 RFC 9421 HTTP
|
package/dist/engine-edge.d.mts
CHANGED
|
@@ -11,11 +11,44 @@ export { DetectionDetail, McpIPayload } from '@kya-os/checkpoint-shared';
|
|
|
11
11
|
* no sync wasm load).
|
|
12
12
|
*
|
|
13
13
|
* This module loads the `wasm-pack --target web` artifact via the
|
|
14
|
-
* async `__wbg_init` default export
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* async `__wbg_init` default export. The web target's `init()`
|
|
15
|
+
* accepts a pre-instantiated `WebAssembly.Module` argument — the
|
|
16
|
+
* canonical Cloudflare-Workers + wasm-bindgen pattern.
|
|
17
|
+
*
|
|
18
|
+
* # Why the caller MUST pass `wasmModule` on Cloudflare Workers
|
|
19
|
+
*
|
|
20
|
+
* Both `--target web` (URL fetch) and `--target bundler` (auto-
|
|
21
|
+
* instantiated `__wbg_set_wasm(wasm)`) have failure modes on wrangler:
|
|
22
|
+
*
|
|
23
|
+
* - `--target web` falls back to `new URL('<wasm>', import.meta.url)`
|
|
24
|
+
* when `init()` is called with no arg. Cloudflare Workers don't
|
|
25
|
+
* materialise `import.meta.url` the way browsers do → throws
|
|
26
|
+
* `TypeError: Invalid URL string`. (Broke production 2026-05-23,
|
|
27
|
+
* captured via dev tail in run 26352287112.)
|
|
28
|
+
*
|
|
29
|
+
* - `--target bundler` expects the host bundler to AUTO-INSTANTIATE
|
|
30
|
+
* `import * as wasm from './foo.wasm'` so `wasm` is the
|
|
31
|
+
* `Instance.exports` object. Webpack does this. **Wrangler does
|
|
32
|
+
* NOT** — wrangler gives you a raw `WebAssembly.Module`, and the
|
|
33
|
+
* bundler-target shim's `__wbg_set_wasm(rawModule)` happily
|
|
34
|
+
* accepts it, then every export lookup (`wasm.__wbindgen_add_
|
|
35
|
+
* to_stack_pointer`, etc.) returns undefined → throws
|
|
36
|
+
* `TypeError: wasm.__wbindgen_add_to_stack_pointer is not a function`.
|
|
37
|
+
* (Broke production 2026-05-24 after switching to bundler target
|
|
38
|
+
* in PR #2785; captured via prod tail.)
|
|
39
|
+
*
|
|
40
|
+
* The fix is the standard Cloudflare-Workers + wasm-bindgen pattern:
|
|
41
|
+
* the consumer statically imports the `.wasm` file (wrangler then
|
|
42
|
+
* bundles it + hands the worker a `WebAssembly.Module`), then passes
|
|
43
|
+
* it to `init(wasmModule)`. The web target's init detects the Module
|
|
44
|
+
* input + calls `WebAssembly.instantiate(Module, imports)` internally
|
|
45
|
+
* to produce a real `Instance` whose exports populate the JS shim's
|
|
46
|
+
* `wasm` binding correctly.
|
|
47
|
+
*
|
|
48
|
+
* Vercel Edge / webpack consumers MAY omit the argument — webpack's
|
|
49
|
+
* async-WASM support handles the URL fetch correctly. But the typed
|
|
50
|
+
* signature here marks `wasmModule` optional for backward compat;
|
|
51
|
+
* Cloudflare-Workers consumers MUST pass it.
|
|
19
52
|
*
|
|
20
53
|
* **Why this matters for the consolidation narrative.** Phase A
|
|
21
54
|
* shipped Node-only. Without an edge build, the first Vercel-edge
|
|
@@ -29,18 +62,21 @@ export { DetectionDetail, McpIPayload } from '@kya-os/checkpoint-shared';
|
|
|
29
62
|
|
|
30
63
|
/**
|
|
31
64
|
* Initialise the edge wasm module. Idempotent — subsequent calls
|
|
32
|
-
* return the same in-flight or resolved promise. Host wrappers
|
|
33
|
-
* call this at startup
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* @param
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
65
|
+
* return the same in-flight or resolved promise. Host wrappers
|
|
66
|
+
* should call this once at startup with the `wasmModule` they
|
|
67
|
+
* statically imported from the package's `./wasm/kya-os-engine-web/`
|
|
68
|
+
* subpath (see CLAUDE.md for the wrangler/webpack import pattern).
|
|
69
|
+
*
|
|
70
|
+
* @param wasmModule REQUIRED on Cloudflare Workers (wrangler hands
|
|
71
|
+
* the consumer a `WebAssembly.Module` from the
|
|
72
|
+
* static `.wasm` import; pass it here so the
|
|
73
|
+
* web-target's `init()` instantiates it). OPTIONAL
|
|
74
|
+
* on Vercel Edge / webpack — webpack's async-WASM
|
|
75
|
+
* support resolves the URL fetch correctly, but
|
|
76
|
+
* passing the module explicitly is recommended
|
|
77
|
+
* for cross-runtime consistency.
|
|
42
78
|
*/
|
|
43
|
-
declare function initEngineEdge(
|
|
79
|
+
declare function initEngineEdge(wasmModule?: WebAssembly.Module | URL | string | Request | BufferSource): Promise<void>;
|
|
44
80
|
/**
|
|
45
81
|
* Edge-runtime async equivalent of `engineVerify`.
|
|
46
82
|
*
|
package/dist/engine-edge.d.ts
CHANGED
|
@@ -11,11 +11,44 @@ export { DetectionDetail, McpIPayload } from '@kya-os/checkpoint-shared';
|
|
|
11
11
|
* no sync wasm load).
|
|
12
12
|
*
|
|
13
13
|
* This module loads the `wasm-pack --target web` artifact via the
|
|
14
|
-
* async `__wbg_init` default export
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
14
|
+
* async `__wbg_init` default export. The web target's `init()`
|
|
15
|
+
* accepts a pre-instantiated `WebAssembly.Module` argument — the
|
|
16
|
+
* canonical Cloudflare-Workers + wasm-bindgen pattern.
|
|
17
|
+
*
|
|
18
|
+
* # Why the caller MUST pass `wasmModule` on Cloudflare Workers
|
|
19
|
+
*
|
|
20
|
+
* Both `--target web` (URL fetch) and `--target bundler` (auto-
|
|
21
|
+
* instantiated `__wbg_set_wasm(wasm)`) have failure modes on wrangler:
|
|
22
|
+
*
|
|
23
|
+
* - `--target web` falls back to `new URL('<wasm>', import.meta.url)`
|
|
24
|
+
* when `init()` is called with no arg. Cloudflare Workers don't
|
|
25
|
+
* materialise `import.meta.url` the way browsers do → throws
|
|
26
|
+
* `TypeError: Invalid URL string`. (Broke production 2026-05-23,
|
|
27
|
+
* captured via dev tail in run 26352287112.)
|
|
28
|
+
*
|
|
29
|
+
* - `--target bundler` expects the host bundler to AUTO-INSTANTIATE
|
|
30
|
+
* `import * as wasm from './foo.wasm'` so `wasm` is the
|
|
31
|
+
* `Instance.exports` object. Webpack does this. **Wrangler does
|
|
32
|
+
* NOT** — wrangler gives you a raw `WebAssembly.Module`, and the
|
|
33
|
+
* bundler-target shim's `__wbg_set_wasm(rawModule)` happily
|
|
34
|
+
* accepts it, then every export lookup (`wasm.__wbindgen_add_
|
|
35
|
+
* to_stack_pointer`, etc.) returns undefined → throws
|
|
36
|
+
* `TypeError: wasm.__wbindgen_add_to_stack_pointer is not a function`.
|
|
37
|
+
* (Broke production 2026-05-24 after switching to bundler target
|
|
38
|
+
* in PR #2785; captured via prod tail.)
|
|
39
|
+
*
|
|
40
|
+
* The fix is the standard Cloudflare-Workers + wasm-bindgen pattern:
|
|
41
|
+
* the consumer statically imports the `.wasm` file (wrangler then
|
|
42
|
+
* bundles it + hands the worker a `WebAssembly.Module`), then passes
|
|
43
|
+
* it to `init(wasmModule)`. The web target's init detects the Module
|
|
44
|
+
* input + calls `WebAssembly.instantiate(Module, imports)` internally
|
|
45
|
+
* to produce a real `Instance` whose exports populate the JS shim's
|
|
46
|
+
* `wasm` binding correctly.
|
|
47
|
+
*
|
|
48
|
+
* Vercel Edge / webpack consumers MAY omit the argument — webpack's
|
|
49
|
+
* async-WASM support handles the URL fetch correctly. But the typed
|
|
50
|
+
* signature here marks `wasmModule` optional for backward compat;
|
|
51
|
+
* Cloudflare-Workers consumers MUST pass it.
|
|
19
52
|
*
|
|
20
53
|
* **Why this matters for the consolidation narrative.** Phase A
|
|
21
54
|
* shipped Node-only. Without an edge build, the first Vercel-edge
|
|
@@ -29,18 +62,21 @@ export { DetectionDetail, McpIPayload } from '@kya-os/checkpoint-shared';
|
|
|
29
62
|
|
|
30
63
|
/**
|
|
31
64
|
* Initialise the edge wasm module. Idempotent — subsequent calls
|
|
32
|
-
* return the same in-flight or resolved promise. Host wrappers
|
|
33
|
-
* call this at startup
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
* @param
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
65
|
+
* return the same in-flight or resolved promise. Host wrappers
|
|
66
|
+
* should call this once at startup with the `wasmModule` they
|
|
67
|
+
* statically imported from the package's `./wasm/kya-os-engine-web/`
|
|
68
|
+
* subpath (see CLAUDE.md for the wrangler/webpack import pattern).
|
|
69
|
+
*
|
|
70
|
+
* @param wasmModule REQUIRED on Cloudflare Workers (wrangler hands
|
|
71
|
+
* the consumer a `WebAssembly.Module` from the
|
|
72
|
+
* static `.wasm` import; pass it here so the
|
|
73
|
+
* web-target's `init()` instantiates it). OPTIONAL
|
|
74
|
+
* on Vercel Edge / webpack — webpack's async-WASM
|
|
75
|
+
* support resolves the URL fetch correctly, but
|
|
76
|
+
* passing the module explicitly is recommended
|
|
77
|
+
* for cross-runtime consistency.
|
|
42
78
|
*/
|
|
43
|
-
declare function initEngineEdge(
|
|
79
|
+
declare function initEngineEdge(wasmModule?: WebAssembly.Module | URL | string | Request | BufferSource): Promise<void>;
|
|
44
80
|
/**
|
|
45
81
|
* Edge-runtime async equivalent of `engineVerify`.
|
|
46
82
|
*
|
package/dist/engine-edge.js
CHANGED
|
@@ -2,20 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
// src/engine/edge.ts
|
|
4
4
|
var initialised = null;
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
var providedModule;
|
|
6
|
+
function initEngineEdge(wasmModule) {
|
|
7
|
+
if (wasmModule !== void 0 && providedModule === void 0) {
|
|
8
|
+
providedModule = wasmModule;
|
|
9
|
+
}
|
|
10
|
+
return ensureReady().then(() => void 0);
|
|
7
11
|
}
|
|
8
|
-
function ensureReady(
|
|
12
|
+
function ensureReady() {
|
|
9
13
|
if (initialised) return initialised;
|
|
10
14
|
const pending = (async () => {
|
|
11
15
|
const mod = await import('@kya-os/checkpoint-wasm-runtime/wasm/kya-os-engine-web/kya_os_engine.js');
|
|
12
|
-
await mod.default(
|
|
16
|
+
await mod.default(
|
|
17
|
+
providedModule !== void 0 ? { module_or_path: providedModule } : void 0
|
|
18
|
+
);
|
|
13
19
|
return mod.verify;
|
|
14
20
|
})();
|
|
15
21
|
initialised = pending;
|
|
16
22
|
pending.catch(() => {
|
|
17
23
|
if (initialised === pending) {
|
|
18
24
|
initialised = null;
|
|
25
|
+
providedModule = void 0;
|
|
19
26
|
}
|
|
20
27
|
});
|
|
21
28
|
return initialised;
|
package/dist/engine-edge.mjs
CHANGED
|
@@ -1,19 +1,26 @@
|
|
|
1
1
|
// src/engine/edge.ts
|
|
2
2
|
var initialised = null;
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
var providedModule;
|
|
4
|
+
function initEngineEdge(wasmModule) {
|
|
5
|
+
if (wasmModule !== void 0 && providedModule === void 0) {
|
|
6
|
+
providedModule = wasmModule;
|
|
7
|
+
}
|
|
8
|
+
return ensureReady().then(() => void 0);
|
|
5
9
|
}
|
|
6
|
-
function ensureReady(
|
|
10
|
+
function ensureReady() {
|
|
7
11
|
if (initialised) return initialised;
|
|
8
12
|
const pending = (async () => {
|
|
9
13
|
const mod = await import('@kya-os/checkpoint-wasm-runtime/wasm/kya-os-engine-web/kya_os_engine.js');
|
|
10
|
-
await mod.default(
|
|
14
|
+
await mod.default(
|
|
15
|
+
providedModule !== void 0 ? { module_or_path: providedModule } : void 0
|
|
16
|
+
);
|
|
11
17
|
return mod.verify;
|
|
12
18
|
})();
|
|
13
19
|
initialised = pending;
|
|
14
20
|
pending.catch(() => {
|
|
15
21
|
if (initialised === pending) {
|
|
16
22
|
initialised = null;
|
|
23
|
+
providedModule = void 0;
|
|
17
24
|
}
|
|
18
25
|
});
|
|
19
26
|
return initialised;
|
package/dist/index.d.mts
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { D as Decision } from './types-C3RniIOM.mjs';
|
|
2
|
+
export { B as BlockReason } from './types-C3RniIOM.mjs';
|
|
3
|
+
import '@kya-os/checkpoint-shared';
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* AgentShield WASM Runtime Types
|
|
3
7
|
*
|
|
@@ -598,6 +602,119 @@ declare class RulesDetector implements IDetector {
|
|
|
598
602
|
*/
|
|
599
603
|
declare function createRulesDetector(): RulesDetector;
|
|
600
604
|
|
|
605
|
+
/**
|
|
606
|
+
* Cedar policy-evaluator bridge — Node fallback.
|
|
607
|
+
*
|
|
608
|
+
* Surfaces the `PolicyEvaluator` class exported by the cedar-enabled
|
|
609
|
+
* `kya-os-engine` WASM artifact (built by
|
|
610
|
+
* `rust/scripts/build-engine-cedar-wasm.sh`, gated on the Rust
|
|
611
|
+
* `wasm,cedar` features). A JS host (the gateway) compiles a tenant
|
|
612
|
+
* policy bundle once and authorizes many requests against it in-process,
|
|
613
|
+
* with no round-trip to a separate policy service.
|
|
614
|
+
*
|
|
615
|
+
* The cedar artifact is a SEPARATE, larger binary than the lean
|
|
616
|
+
* detection artifact — it pulls in `cedar-policy`. Detection-only
|
|
617
|
+
* consumers load `./engine` (the lean `verify()` glue); only callers that
|
|
618
|
+
* need in-process authorization reach for this bridge.
|
|
619
|
+
*
|
|
620
|
+
* ## Lazy loading
|
|
621
|
+
*
|
|
622
|
+
* The cedar `--target nodejs` glue instantiates the ~2 MB cedar WASM the
|
|
623
|
+
* moment it is `require`d (it `fs.readFileSync`s its `.wasm` sibling at
|
|
624
|
+
* module load). To keep the separate-artifact promise — detection-only
|
|
625
|
+
* consumers must NOT pay cedar's memory/startup — the glue is loaded
|
|
626
|
+
* LAZILY: nothing happens on `import`; the artifact is `require`d (and
|
|
627
|
+
* memoised) only on the first {@link createPolicyEvaluator} call. This is
|
|
628
|
+
* also why cedar lives behind the dedicated `./policy` subpath and is NOT
|
|
629
|
+
* re-exported from the `./node` barrel.
|
|
630
|
+
*
|
|
631
|
+
* `createRequire(__filename)` resolves the glue at call time in both
|
|
632
|
+
* builds — native `require` under CJS, the tsup `shims` / `createRequire`
|
|
633
|
+
* banner under ESM. The glue stays external (regex
|
|
634
|
+
* `wasm/kya-os-engine-cedar/` in tsup's `commonOpts.external`), so its
|
|
635
|
+
* `__dirname` resolves against `node_modules/.../wasm/kya-os-engine-cedar/`
|
|
636
|
+
* where the `.wasm` lives, and `"type": "commonjs"` on the artifact's
|
|
637
|
+
* package.json keeps Node from throwing `ERR_REQUIRE_ESM`.
|
|
638
|
+
*
|
|
639
|
+
* Direct .wasm path (for callers building their own loaders):
|
|
640
|
+
* `@kya-os/checkpoint-wasm-runtime/wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm`
|
|
641
|
+
*/
|
|
642
|
+
|
|
643
|
+
/**
|
|
644
|
+
* Owned, plain-data request the host hands to
|
|
645
|
+
* {@link PolicyEvaluatorRuntime.authorize}. Mirrors the Rust
|
|
646
|
+
* `AuthorizeInput` (`rust/crates/kya-os-engine/src/policy/authorize.rs`);
|
|
647
|
+
* keys are camelCase across the wasm-bindgen boundary, matching every
|
|
648
|
+
* other engine wire type.
|
|
649
|
+
*
|
|
650
|
+
* The evaluator is **synchronous over pre-resolved facts** (H-1 Kickoff
|
|
651
|
+
* § 4.5): the host pre-fetches the agent's delegation chain, reputation,
|
|
652
|
+
* etc. and ships the results here — no JS callbacks cross the boundary.
|
|
653
|
+
*
|
|
654
|
+
* `agentDid` and `reputation` are optional (omit or pass `undefined` for
|
|
655
|
+
* an anonymous or reputation-less request); `grantedScopes` defaults to an
|
|
656
|
+
* empty list when omitted.
|
|
657
|
+
*/
|
|
658
|
+
interface AuthorizeInput {
|
|
659
|
+
/** Agent DID if identity has been established, otherwise omitted. */
|
|
660
|
+
agentDid?: string;
|
|
661
|
+
/** The action being requested (e.g., `"book_flight"`). */
|
|
662
|
+
action: string;
|
|
663
|
+
/** The resource being acted on (e.g., `"travel_api"`). */
|
|
664
|
+
resource: string;
|
|
665
|
+
/** Scopes granted by the agent's delegation chain. Defaults to `[]`. */
|
|
666
|
+
grantedScopes?: string[];
|
|
667
|
+
/** Agent's reputation score in `[0.0, 1.0]`, if computed. */
|
|
668
|
+
reputation?: number;
|
|
669
|
+
/** Tenant identifier. */
|
|
670
|
+
tenantId: string;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* Structural type of the WASM `PolicyEvaluator` class the cedar glue
|
|
674
|
+
* exports. Pinned here so this bridge type-checks against the artifact's
|
|
675
|
+
* `.d.ts` (`constructor(policy_text: string)`, `authorize(input): any`,
|
|
676
|
+
* `free()`).
|
|
677
|
+
*/
|
|
678
|
+
interface WasmPolicyEvaluator {
|
|
679
|
+
authorize(input: AuthorizeInput): unknown;
|
|
680
|
+
free(): void;
|
|
681
|
+
}
|
|
682
|
+
/**
|
|
683
|
+
* Host-facing wrapper around one compiled Cedar policy bundle.
|
|
684
|
+
*
|
|
685
|
+
* Construction compiles the bundle once; every {@link authorize} call
|
|
686
|
+
* evaluates a single owned request against it without re-parsing policy
|
|
687
|
+
* text (the compile-once / evaluate-many contract the engine upholds,
|
|
688
|
+
* carried across the boundary).
|
|
689
|
+
*/
|
|
690
|
+
declare class PolicyEvaluatorRuntime {
|
|
691
|
+
private readonly inner;
|
|
692
|
+
/**
|
|
693
|
+
* @param inner - The compiled WASM `PolicyEvaluator` handle. Built in
|
|
694
|
+
* {@link createPolicyEvaluator}; reused by every {@link authorize}
|
|
695
|
+
* call for the lifetime of this wrapper.
|
|
696
|
+
*/
|
|
697
|
+
constructor(inner: WasmPolicyEvaluator);
|
|
698
|
+
/**
|
|
699
|
+
* Authorize one owned request against the compiled policy bundle.
|
|
700
|
+
*
|
|
701
|
+
* The evaluator owns the fail-closed posture — a request it cannot
|
|
702
|
+
* marshal into Cedar, or one matching no `permit`, comes back as a
|
|
703
|
+
* {@link Decision} `Block` (not a thrown error). Authorization
|
|
704
|
+
* *verdicts* never throw; they surface inside the returned value.
|
|
705
|
+
*
|
|
706
|
+
* @throws {Error} only for boundary faults the WASM glue rejects: a
|
|
707
|
+
* malformed `input` that fails `AuthorizeInput` deserialisation, or a
|
|
708
|
+
* failure serialising the resulting `Decision`.
|
|
709
|
+
*/
|
|
710
|
+
authorize(input: AuthorizeInput): Decision;
|
|
711
|
+
/**
|
|
712
|
+
* Release the compiled bundle's WASM memory. Call when the evaluator is
|
|
713
|
+
* no longer needed; after this the wrapper must not be reused.
|
|
714
|
+
*/
|
|
715
|
+
free(): void;
|
|
716
|
+
}
|
|
717
|
+
|
|
601
718
|
/**
|
|
602
719
|
* Create a detector with automatic runtime selection
|
|
603
720
|
*
|
|
@@ -650,4 +767,4 @@ declare function createEdgeDetector(wasmModule: WebAssembly.Module, options?: ID
|
|
|
650
767
|
*/
|
|
651
768
|
declare function createFallbackDetector(): IDetector;
|
|
652
769
|
|
|
653
|
-
export { CONFIDENCE, type DetectionClass, DynamicWasmLoader, type ForgeabilityRisk, type ICustomerPolicy, type IDetectedAgent, type IDetectionInput, type IDetectionResult, type IDetector, type IDetectorOptions, type IPathRule, type IPolicyLoader, type IWasmBindings, type IWasmLoader, PolicyLoadError, PolicyLoader, type PolicyLoaderConfig, RulesDetector, StaticWasmLoader, type VerificationMethod, WasmDetector, createDetector, createDynamicLoader, createEdgeDetector, createFallbackDetector, createPolicyLoader, createRulesDetector, createStaticLoader };
|
|
770
|
+
export { type AuthorizeInput, CONFIDENCE, Decision, type DetectionClass, DynamicWasmLoader, type ForgeabilityRisk, type ICustomerPolicy, type IDetectedAgent, type IDetectionInput, type IDetectionResult, type IDetector, type IDetectorOptions, type IPathRule, type IPolicyLoader, type IWasmBindings, type IWasmLoader, PolicyEvaluatorRuntime, PolicyLoadError, PolicyLoader, type PolicyLoaderConfig, RulesDetector, StaticWasmLoader, type VerificationMethod, WasmDetector, createDetector, createDynamicLoader, createEdgeDetector, createFallbackDetector, createPolicyLoader, createRulesDetector, createStaticLoader };
|