@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.
Files changed (45) hide show
  1. package/CHANGELOG.md +215 -0
  2. package/dist/engine-edge.d.mts +52 -16
  3. package/dist/engine-edge.d.ts +52 -16
  4. package/dist/engine-edge.js +11 -4
  5. package/dist/engine-edge.mjs +11 -4
  6. package/dist/index.d.mts +118 -1
  7. package/dist/index.d.ts +118 -1
  8. package/dist/orchestrator-edge.js +46 -13
  9. package/dist/orchestrator-edge.mjs +46 -13
  10. package/dist/orchestrator-node.js +35 -9
  11. package/dist/orchestrator-node.mjs +35 -9
  12. package/dist/orchestrator.d.mts +52 -16
  13. package/dist/orchestrator.d.ts +52 -16
  14. package/dist/orchestrator.js +46 -13
  15. package/dist/orchestrator.mjs +46 -13
  16. package/dist/policy.d.mts +148 -0
  17. package/dist/policy.d.ts +148 -0
  18. package/dist/policy.js +52 -0
  19. package/dist/policy.mjs +53 -0
  20. package/dist/reporter.d.mts +102 -0
  21. package/dist/reporter.d.ts +102 -0
  22. package/dist/reporter.js +125 -0
  23. package/dist/reporter.mjs +122 -0
  24. package/package.json +15 -5
  25. package/wasm/kya-os-engine/kya_os_engine_bg.wasm +0 -0
  26. package/wasm/kya-os-engine/package.json +4 -2
  27. package/wasm/kya-os-engine-bundler/kya_os_engine_bg.wasm +0 -0
  28. package/wasm/kya-os-engine-cedar/README.md +26 -0
  29. package/wasm/kya-os-engine-cedar/kya_os_engine.d.ts +77 -0
  30. package/wasm/kya-os-engine-cedar/kya_os_engine.js +636 -0
  31. package/wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm +0 -0
  32. package/wasm/kya-os-engine-cedar/kya_os_engine_bg.wasm.d.ts +11 -0
  33. package/wasm/kya-os-engine-cedar/package.json +29 -0
  34. package/wasm/kya-os-engine-cedar-web/README.md +26 -0
  35. package/wasm/kya-os-engine-cedar-web/kya_os_engine.d.ts +117 -0
  36. package/wasm/kya-os-engine-cedar-web/kya_os_engine.js +694 -0
  37. package/wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm +0 -0
  38. package/wasm/kya-os-engine-cedar-web/kya_os_engine_bg.wasm.d.ts +11 -0
  39. package/wasm/kya-os-engine-cedar-web/package.json +31 -0
  40. package/wasm/kya-os-engine-web/kya_os_engine_bg.wasm +0 -0
  41. package/wasm/kya-os-engine-web/package.json +5 -3
  42. package/wasm/agentshield_wasm.d.ts +0 -485
  43. package/wasm/agentshield_wasm.js +0 -1551
  44. package/wasm/agentshield_wasm_bg.wasm +0 -0
  45. package/wasm/agentshield_wasm_bg.wasm.d.ts +0 -97
package/dist/index.d.ts CHANGED
@@ -1,3 +1,7 @@
1
+ import { D as Decision } from './types-C3RniIOM.js';
2
+ export { B as BlockReason } from './types-C3RniIOM.js';
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 };
@@ -77,20 +77,27 @@ function isBlockedIpv6(hostname) {
77
77
 
78
78
  // src/engine/edge.ts
79
79
  var initialised = null;
80
- function initEngineEdge(moduleOrPath) {
81
- return ensureReady(moduleOrPath).then(() => void 0);
80
+ var providedModule;
81
+ function initEngineEdge(wasmModule) {
82
+ if (wasmModule !== void 0 && providedModule === void 0) {
83
+ providedModule = wasmModule;
84
+ }
85
+ return ensureReady().then(() => void 0);
82
86
  }
83
- function ensureReady(moduleOrPath) {
87
+ function ensureReady() {
84
88
  if (initialised) return initialised;
85
89
  const pending = (async () => {
86
90
  const mod = await import('@kya-os/checkpoint-wasm-runtime/wasm/kya-os-engine-web/kya_os_engine.js');
87
- await mod.default(moduleOrPath !== void 0 ? { module_or_path: moduleOrPath } : void 0);
91
+ await mod.default(
92
+ providedModule !== void 0 ? { module_or_path: providedModule } : void 0
93
+ );
88
94
  return mod.verify;
89
95
  })();
90
96
  initialised = pending;
91
97
  pending.catch(() => {
92
98
  if (initialised === pending) {
93
99
  initialised = null;
100
+ providedModule = void 0;
94
101
  }
95
102
  });
96
103
  return initialised;
@@ -191,21 +198,30 @@ function parseBodyAsObject(body) {
191
198
  function tryBuildMcpIFromLegacyHeader(req) {
192
199
  const header = getHeader(req, "kya-delegation");
193
200
  if (!header) return null;
194
- let parsed;
201
+ let parsed = void 0;
195
202
  try {
196
203
  parsed = JSON.parse(header);
197
204
  } catch {
198
- return null;
199
205
  }
200
- if (!parsed || typeof parsed !== "object") return null;
201
- const obj = parsed;
202
- const protectedSeg = obj.protected;
203
- const payloadSeg = obj.payload;
204
- const signatureSeg = obj.signature;
205
- if (typeof protectedSeg !== "string" || typeof payloadSeg !== "string" || typeof signatureSeg !== "string") {
206
+ if (parsed && typeof parsed === "object") {
207
+ const obj = parsed;
208
+ const protectedSeg = obj.protected;
209
+ const payloadSeg = obj.payload;
210
+ const signatureSeg = obj.signature;
211
+ if (typeof protectedSeg === "string" && typeof payloadSeg === "string" && typeof signatureSeg === "string") {
212
+ const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
213
+ return buildMcpIRequestFromCompact(compact);
214
+ }
206
215
  return null;
207
216
  }
208
- const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
217
+ const trimmed = header.trim();
218
+ if (COMPACT_JWS_PATTERN.test(trimmed)) {
219
+ return buildMcpIRequestFromCompact(trimmed);
220
+ }
221
+ return null;
222
+ }
223
+ var COMPACT_JWS_PATTERN = /^[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*$/;
224
+ function buildMcpIRequestFromCompact(compact) {
209
225
  const raw = Array.from(Buffer.from(compact, "utf8"));
210
226
  const payload = parseJwsPayloadStruct(raw);
211
227
  if (!payload) return null;
@@ -404,6 +420,23 @@ function buildBaseHeaders(result) {
404
420
  if (result.engineInfo.rulesetHash) {
405
421
  headers["X-Checkpoint-Ruleset-Hash"] = result.engineInfo.rulesetHash;
406
422
  }
423
+ const meta = result.detectionDetail.metadata;
424
+ if (meta) {
425
+ const verifiedTier = meta.verified_tier;
426
+ if (typeof verifiedTier === "number" && Number.isFinite(verifiedTier)) {
427
+ headers["X-Checkpoint-Verified-Tier"] = String(verifiedTier);
428
+ } else if (typeof verifiedTier === "string" && verifiedTier.length > 0) {
429
+ headers["X-Checkpoint-Verified-Tier"] = verifiedTier;
430
+ }
431
+ const verifiedVendor = meta.verified_vendor;
432
+ if (typeof verifiedVendor === "string" && verifiedVendor.length > 0) {
433
+ headers["X-Checkpoint-Verified-Vendor"] = verifiedVendor;
434
+ }
435
+ const verifiedProtocol = meta.verified_protocol;
436
+ if (typeof verifiedProtocol === "string" && verifiedProtocol.length > 0) {
437
+ headers["X-Checkpoint-Verified-Protocol"] = verifiedProtocol;
438
+ }
439
+ }
407
440
  return headers;
408
441
  }
409
442
  function httpStatusForBlockReason(reason) {
@@ -75,20 +75,27 @@ function isBlockedIpv6(hostname) {
75
75
 
76
76
  // src/engine/edge.ts
77
77
  var initialised = null;
78
- function initEngineEdge(moduleOrPath) {
79
- return ensureReady(moduleOrPath).then(() => void 0);
78
+ var providedModule;
79
+ function initEngineEdge(wasmModule) {
80
+ if (wasmModule !== void 0 && providedModule === void 0) {
81
+ providedModule = wasmModule;
82
+ }
83
+ return ensureReady().then(() => void 0);
80
84
  }
81
- function ensureReady(moduleOrPath) {
85
+ function ensureReady() {
82
86
  if (initialised) return initialised;
83
87
  const pending = (async () => {
84
88
  const mod = await import('@kya-os/checkpoint-wasm-runtime/wasm/kya-os-engine-web/kya_os_engine.js');
85
- await mod.default(moduleOrPath !== void 0 ? { module_or_path: moduleOrPath } : void 0);
89
+ await mod.default(
90
+ providedModule !== void 0 ? { module_or_path: providedModule } : void 0
91
+ );
86
92
  return mod.verify;
87
93
  })();
88
94
  initialised = pending;
89
95
  pending.catch(() => {
90
96
  if (initialised === pending) {
91
97
  initialised = null;
98
+ providedModule = void 0;
92
99
  }
93
100
  });
94
101
  return initialised;
@@ -189,21 +196,30 @@ function parseBodyAsObject(body) {
189
196
  function tryBuildMcpIFromLegacyHeader(req) {
190
197
  const header = getHeader(req, "kya-delegation");
191
198
  if (!header) return null;
192
- let parsed;
199
+ let parsed = void 0;
193
200
  try {
194
201
  parsed = JSON.parse(header);
195
202
  } catch {
196
- return null;
197
203
  }
198
- if (!parsed || typeof parsed !== "object") return null;
199
- const obj = parsed;
200
- const protectedSeg = obj.protected;
201
- const payloadSeg = obj.payload;
202
- const signatureSeg = obj.signature;
203
- if (typeof protectedSeg !== "string" || typeof payloadSeg !== "string" || typeof signatureSeg !== "string") {
204
+ if (parsed && typeof parsed === "object") {
205
+ const obj = parsed;
206
+ const protectedSeg = obj.protected;
207
+ const payloadSeg = obj.payload;
208
+ const signatureSeg = obj.signature;
209
+ if (typeof protectedSeg === "string" && typeof payloadSeg === "string" && typeof signatureSeg === "string") {
210
+ const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
211
+ return buildMcpIRequestFromCompact(compact);
212
+ }
204
213
  return null;
205
214
  }
206
- const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
215
+ const trimmed = header.trim();
216
+ if (COMPACT_JWS_PATTERN.test(trimmed)) {
217
+ return buildMcpIRequestFromCompact(trimmed);
218
+ }
219
+ return null;
220
+ }
221
+ var COMPACT_JWS_PATTERN = /^[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*$/;
222
+ function buildMcpIRequestFromCompact(compact) {
207
223
  const raw = Array.from(Buffer.from(compact, "utf8"));
208
224
  const payload = parseJwsPayloadStruct(raw);
209
225
  if (!payload) return null;
@@ -402,6 +418,23 @@ function buildBaseHeaders(result) {
402
418
  if (result.engineInfo.rulesetHash) {
403
419
  headers["X-Checkpoint-Ruleset-Hash"] = result.engineInfo.rulesetHash;
404
420
  }
421
+ const meta = result.detectionDetail.metadata;
422
+ if (meta) {
423
+ const verifiedTier = meta.verified_tier;
424
+ if (typeof verifiedTier === "number" && Number.isFinite(verifiedTier)) {
425
+ headers["X-Checkpoint-Verified-Tier"] = String(verifiedTier);
426
+ } else if (typeof verifiedTier === "string" && verifiedTier.length > 0) {
427
+ headers["X-Checkpoint-Verified-Tier"] = verifiedTier;
428
+ }
429
+ const verifiedVendor = meta.verified_vendor;
430
+ if (typeof verifiedVendor === "string" && verifiedVendor.length > 0) {
431
+ headers["X-Checkpoint-Verified-Vendor"] = verifiedVendor;
432
+ }
433
+ const verifiedProtocol = meta.verified_protocol;
434
+ if (typeof verifiedProtocol === "string" && verifiedProtocol.length > 0) {
435
+ headers["X-Checkpoint-Verified-Protocol"] = verifiedProtocol;
436
+ }
437
+ }
405
438
  return headers;
406
439
  }
407
440
  function httpStatusForBlockReason(reason) {
@@ -194,21 +194,30 @@ function parseBodyAsObject(body) {
194
194
  function tryBuildMcpIFromLegacyHeader(req) {
195
195
  const header = getHeader(req, "kya-delegation");
196
196
  if (!header) return null;
197
- let parsed;
197
+ let parsed = void 0;
198
198
  try {
199
199
  parsed = JSON.parse(header);
200
200
  } catch {
201
- return null;
202
201
  }
203
- if (!parsed || typeof parsed !== "object") return null;
204
- const obj = parsed;
205
- const protectedSeg = obj.protected;
206
- const payloadSeg = obj.payload;
207
- const signatureSeg = obj.signature;
208
- if (typeof protectedSeg !== "string" || typeof payloadSeg !== "string" || typeof signatureSeg !== "string") {
202
+ if (parsed && typeof parsed === "object") {
203
+ const obj = parsed;
204
+ const protectedSeg = obj.protected;
205
+ const payloadSeg = obj.payload;
206
+ const signatureSeg = obj.signature;
207
+ if (typeof protectedSeg === "string" && typeof payloadSeg === "string" && typeof signatureSeg === "string") {
208
+ const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
209
+ return buildMcpIRequestFromCompact(compact);
210
+ }
209
211
  return null;
210
212
  }
211
- const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
213
+ const trimmed = header.trim();
214
+ if (COMPACT_JWS_PATTERN.test(trimmed)) {
215
+ return buildMcpIRequestFromCompact(trimmed);
216
+ }
217
+ return null;
218
+ }
219
+ var COMPACT_JWS_PATTERN = /^[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*$/;
220
+ function buildMcpIRequestFromCompact(compact) {
212
221
  const raw = Array.from(Buffer.from(compact, "utf8"));
213
222
  const payload = parseJwsPayloadStruct(raw);
214
223
  if (!payload) return null;
@@ -508,6 +517,23 @@ function buildBaseHeaders(result) {
508
517
  if (result.engineInfo.rulesetHash) {
509
518
  headers["X-Checkpoint-Ruleset-Hash"] = result.engineInfo.rulesetHash;
510
519
  }
520
+ const meta = result.detectionDetail.metadata;
521
+ if (meta) {
522
+ const verifiedTier = meta.verified_tier;
523
+ if (typeof verifiedTier === "number" && Number.isFinite(verifiedTier)) {
524
+ headers["X-Checkpoint-Verified-Tier"] = String(verifiedTier);
525
+ } else if (typeof verifiedTier === "string" && verifiedTier.length > 0) {
526
+ headers["X-Checkpoint-Verified-Tier"] = verifiedTier;
527
+ }
528
+ const verifiedVendor = meta.verified_vendor;
529
+ if (typeof verifiedVendor === "string" && verifiedVendor.length > 0) {
530
+ headers["X-Checkpoint-Verified-Vendor"] = verifiedVendor;
531
+ }
532
+ const verifiedProtocol = meta.verified_protocol;
533
+ if (typeof verifiedProtocol === "string" && verifiedProtocol.length > 0) {
534
+ headers["X-Checkpoint-Verified-Protocol"] = verifiedProtocol;
535
+ }
536
+ }
511
537
  return headers;
512
538
  }
513
539
  function httpStatusForBlockReason(reason) {
@@ -173,21 +173,30 @@ function parseBodyAsObject(body) {
173
173
  function tryBuildMcpIFromLegacyHeader(req) {
174
174
  const header = getHeader(req, "kya-delegation");
175
175
  if (!header) return null;
176
- let parsed;
176
+ let parsed = void 0;
177
177
  try {
178
178
  parsed = JSON.parse(header);
179
179
  } catch {
180
- return null;
181
180
  }
182
- if (!parsed || typeof parsed !== "object") return null;
183
- const obj = parsed;
184
- const protectedSeg = obj.protected;
185
- const payloadSeg = obj.payload;
186
- const signatureSeg = obj.signature;
187
- if (typeof protectedSeg !== "string" || typeof payloadSeg !== "string" || typeof signatureSeg !== "string") {
181
+ if (parsed && typeof parsed === "object") {
182
+ const obj = parsed;
183
+ const protectedSeg = obj.protected;
184
+ const payloadSeg = obj.payload;
185
+ const signatureSeg = obj.signature;
186
+ if (typeof protectedSeg === "string" && typeof payloadSeg === "string" && typeof signatureSeg === "string") {
187
+ const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
188
+ return buildMcpIRequestFromCompact(compact);
189
+ }
188
190
  return null;
189
191
  }
190
- const compact = `${protectedSeg}.${payloadSeg}.${signatureSeg}`;
192
+ const trimmed = header.trim();
193
+ if (COMPACT_JWS_PATTERN.test(trimmed)) {
194
+ return buildMcpIRequestFromCompact(trimmed);
195
+ }
196
+ return null;
197
+ }
198
+ var COMPACT_JWS_PATTERN = /^[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*\.[A-Za-z0-9_-]+=*$/;
199
+ function buildMcpIRequestFromCompact(compact) {
191
200
  const raw = Array.from(Buffer.from(compact, "utf8"));
192
201
  const payload = parseJwsPayloadStruct(raw);
193
202
  if (!payload) return null;
@@ -487,6 +496,23 @@ function buildBaseHeaders(result) {
487
496
  if (result.engineInfo.rulesetHash) {
488
497
  headers["X-Checkpoint-Ruleset-Hash"] = result.engineInfo.rulesetHash;
489
498
  }
499
+ const meta = result.detectionDetail.metadata;
500
+ if (meta) {
501
+ const verifiedTier = meta.verified_tier;
502
+ if (typeof verifiedTier === "number" && Number.isFinite(verifiedTier)) {
503
+ headers["X-Checkpoint-Verified-Tier"] = String(verifiedTier);
504
+ } else if (typeof verifiedTier === "string" && verifiedTier.length > 0) {
505
+ headers["X-Checkpoint-Verified-Tier"] = verifiedTier;
506
+ }
507
+ const verifiedVendor = meta.verified_vendor;
508
+ if (typeof verifiedVendor === "string" && verifiedVendor.length > 0) {
509
+ headers["X-Checkpoint-Verified-Vendor"] = verifiedVendor;
510
+ }
511
+ const verifiedProtocol = meta.verified_protocol;
512
+ if (typeof verifiedProtocol === "string" && verifiedProtocol.length > 0) {
513
+ headers["X-Checkpoint-Verified-Protocol"] = verifiedProtocol;
514
+ }
515
+ }
490
516
  return headers;
491
517
  }
492
518
  function httpStatusForBlockReason(reason) {
@@ -222,11 +222,44 @@ interface RenderedResponse {
222
222
  * no sync wasm load).
223
223
  *
224
224
  * This module loads the `wasm-pack --target web` artifact via the
225
- * async `__wbg_init` default export, then exposes the same typed
226
- * `engineVerifyEdge(input, ctx) Promise<VerifyResult>` shape with
227
- * a small lazy-init wrapper. First call awaits initialisation;
228
- * subsequent calls resolve synchronously on the JS side (the
229
- * underlying wasm `verify` is sync).
225
+ * async `__wbg_init` default export. The web target's `init()`
226
+ * accepts a pre-instantiated `WebAssembly.Module` argument — the
227
+ * canonical Cloudflare-Workers + wasm-bindgen pattern.
228
+ *
229
+ * # Why the caller MUST pass `wasmModule` on Cloudflare Workers
230
+ *
231
+ * Both `--target web` (URL fetch) and `--target bundler` (auto-
232
+ * instantiated `__wbg_set_wasm(wasm)`) have failure modes on wrangler:
233
+ *
234
+ * - `--target web` falls back to `new URL('<wasm>', import.meta.url)`
235
+ * when `init()` is called with no arg. Cloudflare Workers don't
236
+ * materialise `import.meta.url` the way browsers do → throws
237
+ * `TypeError: Invalid URL string`. (Broke production 2026-05-23,
238
+ * captured via dev tail in run 26352287112.)
239
+ *
240
+ * - `--target bundler` expects the host bundler to AUTO-INSTANTIATE
241
+ * `import * as wasm from './foo.wasm'` so `wasm` is the
242
+ * `Instance.exports` object. Webpack does this. **Wrangler does
243
+ * NOT** — wrangler gives you a raw `WebAssembly.Module`, and the
244
+ * bundler-target shim's `__wbg_set_wasm(rawModule)` happily
245
+ * accepts it, then every export lookup (`wasm.__wbindgen_add_
246
+ * to_stack_pointer`, etc.) returns undefined → throws
247
+ * `TypeError: wasm.__wbindgen_add_to_stack_pointer is not a function`.
248
+ * (Broke production 2026-05-24 after switching to bundler target
249
+ * in PR #2785; captured via prod tail.)
250
+ *
251
+ * The fix is the standard Cloudflare-Workers + wasm-bindgen pattern:
252
+ * the consumer statically imports the `.wasm` file (wrangler then
253
+ * bundles it + hands the worker a `WebAssembly.Module`), then passes
254
+ * it to `init(wasmModule)`. The web target's init detects the Module
255
+ * input + calls `WebAssembly.instantiate(Module, imports)` internally
256
+ * to produce a real `Instance` whose exports populate the JS shim's
257
+ * `wasm` binding correctly.
258
+ *
259
+ * Vercel Edge / webpack consumers MAY omit the argument — webpack's
260
+ * async-WASM support handles the URL fetch correctly. But the typed
261
+ * signature here marks `wasmModule` optional for backward compat;
262
+ * Cloudflare-Workers consumers MUST pass it.
230
263
  *
231
264
  * **Why this matters for the consolidation narrative.** Phase A
232
265
  * shipped Node-only. Without an edge build, the first Vercel-edge
@@ -240,18 +273,21 @@ interface RenderedResponse {
240
273
 
241
274
  /**
242
275
  * Initialise the edge wasm module. Idempotent — subsequent calls
243
- * return the same in-flight or resolved promise. Host wrappers can
244
- * call this at startup to eagerly load the wasm and avoid first-
245
- * request latency, but it's not required: `engineVerifyEdge`
246
- * lazily initialises on first call.
247
- *
248
- * @param moduleOrPath Optional pre-fetched `WebAssembly.Module` or
249
- * a URL / Request the wasm-bindgen loader will
250
- * fetch. Defaults to the bundled artifact via
251
- * `import.meta.url`. Cloudflare Workers / Vercel
252
- * Edge typically pass a pre-bundled `Module`.
276
+ * return the same in-flight or resolved promise. Host wrappers
277
+ * should call this once at startup with the `wasmModule` they
278
+ * statically imported from the package's `./wasm/kya-os-engine-web/`
279
+ * subpath (see CLAUDE.md for the wrangler/webpack import pattern).
280
+ *
281
+ * @param wasmModule REQUIRED on Cloudflare Workers (wrangler hands
282
+ * the consumer a `WebAssembly.Module` from the
283
+ * static `.wasm` import; pass it here so the
284
+ * web-target's `init()` instantiates it). OPTIONAL
285
+ * on Vercel Edge / webpack webpack's async-WASM
286
+ * support resolves the URL fetch correctly, but
287
+ * passing the module explicitly is recommended
288
+ * for cross-runtime consistency.
253
289
  */
254
- declare function initEngineEdge(moduleOrPath?: WebAssembly.Module | URL | string | Request | BufferSource): Promise<void>;
290
+ declare function initEngineEdge(wasmModule?: WebAssembly.Module | URL | string | Request | BufferSource): Promise<void>;
255
291
 
256
292
  /**
257
293
  * HTTP-to-`AgentRequest` translator — Phase C.1.
@@ -222,11 +222,44 @@ interface RenderedResponse {
222
222
  * no sync wasm load).
223
223
  *
224
224
  * This module loads the `wasm-pack --target web` artifact via the
225
- * async `__wbg_init` default export, then exposes the same typed
226
- * `engineVerifyEdge(input, ctx) Promise<VerifyResult>` shape with
227
- * a small lazy-init wrapper. First call awaits initialisation;
228
- * subsequent calls resolve synchronously on the JS side (the
229
- * underlying wasm `verify` is sync).
225
+ * async `__wbg_init` default export. The web target's `init()`
226
+ * accepts a pre-instantiated `WebAssembly.Module` argument — the
227
+ * canonical Cloudflare-Workers + wasm-bindgen pattern.
228
+ *
229
+ * # Why the caller MUST pass `wasmModule` on Cloudflare Workers
230
+ *
231
+ * Both `--target web` (URL fetch) and `--target bundler` (auto-
232
+ * instantiated `__wbg_set_wasm(wasm)`) have failure modes on wrangler:
233
+ *
234
+ * - `--target web` falls back to `new URL('<wasm>', import.meta.url)`
235
+ * when `init()` is called with no arg. Cloudflare Workers don't
236
+ * materialise `import.meta.url` the way browsers do → throws
237
+ * `TypeError: Invalid URL string`. (Broke production 2026-05-23,
238
+ * captured via dev tail in run 26352287112.)
239
+ *
240
+ * - `--target bundler` expects the host bundler to AUTO-INSTANTIATE
241
+ * `import * as wasm from './foo.wasm'` so `wasm` is the
242
+ * `Instance.exports` object. Webpack does this. **Wrangler does
243
+ * NOT** — wrangler gives you a raw `WebAssembly.Module`, and the
244
+ * bundler-target shim's `__wbg_set_wasm(rawModule)` happily
245
+ * accepts it, then every export lookup (`wasm.__wbindgen_add_
246
+ * to_stack_pointer`, etc.) returns undefined → throws
247
+ * `TypeError: wasm.__wbindgen_add_to_stack_pointer is not a function`.
248
+ * (Broke production 2026-05-24 after switching to bundler target
249
+ * in PR #2785; captured via prod tail.)
250
+ *
251
+ * The fix is the standard Cloudflare-Workers + wasm-bindgen pattern:
252
+ * the consumer statically imports the `.wasm` file (wrangler then
253
+ * bundles it + hands the worker a `WebAssembly.Module`), then passes
254
+ * it to `init(wasmModule)`. The web target's init detects the Module
255
+ * input + calls `WebAssembly.instantiate(Module, imports)` internally
256
+ * to produce a real `Instance` whose exports populate the JS shim's
257
+ * `wasm` binding correctly.
258
+ *
259
+ * Vercel Edge / webpack consumers MAY omit the argument — webpack's
260
+ * async-WASM support handles the URL fetch correctly. But the typed
261
+ * signature here marks `wasmModule` optional for backward compat;
262
+ * Cloudflare-Workers consumers MUST pass it.
230
263
  *
231
264
  * **Why this matters for the consolidation narrative.** Phase A
232
265
  * shipped Node-only. Without an edge build, the first Vercel-edge
@@ -240,18 +273,21 @@ interface RenderedResponse {
240
273
 
241
274
  /**
242
275
  * Initialise the edge wasm module. Idempotent — subsequent calls
243
- * return the same in-flight or resolved promise. Host wrappers can
244
- * call this at startup to eagerly load the wasm and avoid first-
245
- * request latency, but it's not required: `engineVerifyEdge`
246
- * lazily initialises on first call.
247
- *
248
- * @param moduleOrPath Optional pre-fetched `WebAssembly.Module` or
249
- * a URL / Request the wasm-bindgen loader will
250
- * fetch. Defaults to the bundled artifact via
251
- * `import.meta.url`. Cloudflare Workers / Vercel
252
- * Edge typically pass a pre-bundled `Module`.
276
+ * return the same in-flight or resolved promise. Host wrappers
277
+ * should call this once at startup with the `wasmModule` they
278
+ * statically imported from the package's `./wasm/kya-os-engine-web/`
279
+ * subpath (see CLAUDE.md for the wrangler/webpack import pattern).
280
+ *
281
+ * @param wasmModule REQUIRED on Cloudflare Workers (wrangler hands
282
+ * the consumer a `WebAssembly.Module` from the
283
+ * static `.wasm` import; pass it here so the
284
+ * web-target's `init()` instantiates it). OPTIONAL
285
+ * on Vercel Edge / webpack webpack's async-WASM
286
+ * support resolves the URL fetch correctly, but
287
+ * passing the module explicitly is recommended
288
+ * for cross-runtime consistency.
253
289
  */
254
- declare function initEngineEdge(moduleOrPath?: WebAssembly.Module | URL | string | Request | BufferSource): Promise<void>;
290
+ declare function initEngineEdge(wasmModule?: WebAssembly.Module | URL | string | Request | BufferSource): Promise<void>;
255
291
 
256
292
  /**
257
293
  * HTTP-to-`AgentRequest` translator — Phase C.1.