@ainra/middleware 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,10 @@
1
1
  import { Verifier, type LinkIndex, type StatusPublication, type LinkVerdict, type Verdict, type VerdictEvent, type DecisionLog } from "@ainra/sdk";
2
+ /** The verdict event as an HTTP header value (2026-11-12). The event's `name` comes from the presenter's own claims,
3
+ * also when the bundle is refused, and `serializeVerdictEvent` keeps non-ASCII as it is (it must byte-match the Rust
4
+ * emitter). A header cannot hold most of those characters: Node's `setHeader` throws on them, which turned a refusal
5
+ * into a 500 in a framework that catches, and stopped a server whose handler did not. So every character outside
6
+ * printable ASCII is written as its JSON `\uXXXX` escape: still valid JSON, and it parses to exactly the same event. */
7
+ export declare function verdictHeaderValue(e: VerdictEvent): string;
2
8
  /** Where the gate keeps bundles a running copy has sent once. Only bundles that verified VALID when they arrived
3
9
  * are ever stored, the key is the SHA-256 of the content, and every request re-verifies what it names — so the
4
10
  * store can lose entries (the client just sends again) but cannot make anything pass that would not. */
package/dist/index.js CHANGED
@@ -9,6 +9,14 @@
9
9
  //! * `checkRequest(verifier, bundle, opts)` → framework-agnostic `{ allow, reason?, verdict }` (edge/fetch).
10
10
  import { verdictEvent, serializeVerdictEvent, decodeInstance, verifyPresentation, isPresentationRef, splitPresentation, joinPresentation, presentationRef, POP_HEADER, PRIME_PATH, decisionRequestDigest, linkFromIndex, presentedKeyThumbprint, } from "@ainra/sdk";
11
11
  import { createHash } from "node:crypto";
12
+ /** The verdict event as an HTTP header value (2026-11-12). The event's `name` comes from the presenter's own claims,
13
+ * also when the bundle is refused, and `serializeVerdictEvent` keeps non-ASCII as it is (it must byte-match the Rust
14
+ * emitter). A header cannot hold most of those characters: Node's `setHeader` throws on them, which turned a refusal
15
+ * into a 500 in a framework that catches, and stopped a server whose handler did not. So every character outside
16
+ * printable ASCII is written as its JSON `\uXXXX` escape: still valid JSON, and it parses to exactly the same event. */
17
+ export function verdictHeaderValue(e) {
18
+ return serializeVerdictEvent(e).replace(/[^\x20-\x7e]/g, (c) => "\\u" + c.charCodeAt(0).toString(16).padStart(4, "0"));
19
+ }
12
20
  /** The default store: in memory, bounded, oldest-first eviction, and nothing outlives the credential it holds.
13
21
  * Bounded because whoever can mint valid bundles can otherwise fill it; eviction costs them nothing but costs an
14
22
  * honest client one re-send, which is the right way round. One process only — behind several, share a store. */
@@ -218,7 +226,7 @@ export function ainraGate(verifier, opts = {}) {
218
226
  if (opts.decisions)
219
227
  recordDecision(opts.decisions, raw, result, req, opts);
220
228
  // Emit the canonical verdict event on every request (allow or deny) — one event shape everywhere (PRESENTATION.md).
221
- res.setHeader("x-ainra-verdict", serializeVerdictEvent(result.event));
229
+ res.setHeader("x-ainra-verdict", verdictHeaderValue(result.event));
222
230
  if (result.allow) {
223
231
  next();
224
232
  return;
@@ -271,7 +279,7 @@ export function ainraPrime(verifier, opts) {
271
279
  if ((req.method ?? "POST").toUpperCase() !== "POST")
272
280
  return deny("schema_violation");
273
281
  const result = checkRequest(verifier, body, { now: () => now });
274
- res.setHeader("x-ainra-verdict", serializeVerdictEvent(result.event));
282
+ res.setHeader("x-ainra-verdict", verdictHeaderValue(result.event));
275
283
  if (!result.allow)
276
284
  return deny(result.reason ?? "schema_violation");
277
285
  const bundle = body;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ainra/middleware",
3
- "version": "0.8.0",
3
+ "version": "0.8.1",
4
4
  "description": "AINRA verifier middleware — a fail-closed gate (Connect/Express + framework-agnostic) that verifies an AINRA passport on a request, over @ainra/sdk. The verification wedge: local, offline, ~5-line integration.",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "type": "module",
@@ -14,7 +14,7 @@
14
14
  "test": "node --test"
15
15
  },
16
16
  "dependencies": {
17
- "@ainra/sdk": "^0.8.0"
17
+ "@ainra/sdk": "^0.8.1"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/node": "^26.1.1",