eve-ai-governance 0.2.0 → 0.3.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 (131) hide show
  1. package/README.md +44 -39
  2. package/dist/cjs/attestation.d.ts +29 -0
  3. package/dist/cjs/attestation.d.ts.map +1 -0
  4. package/dist/cjs/attestation.js +42 -0
  5. package/dist/cjs/attestation.js.map +1 -0
  6. package/dist/cjs/canonical.d.ts +51 -0
  7. package/dist/cjs/canonical.d.ts.map +1 -0
  8. package/dist/cjs/canonical.js +168 -0
  9. package/dist/cjs/canonical.js.map +1 -0
  10. package/dist/cjs/decision-web.d.ts +29 -0
  11. package/dist/cjs/decision-web.d.ts.map +1 -0
  12. package/dist/cjs/decision-web.js +315 -0
  13. package/dist/cjs/decision-web.js.map +1 -0
  14. package/dist/cjs/decision.d.ts +62 -0
  15. package/dist/cjs/decision.d.ts.map +1 -0
  16. package/dist/cjs/decision.js +317 -0
  17. package/dist/cjs/decision.js.map +1 -0
  18. package/dist/cjs/index.d.ts +31 -3
  19. package/dist/cjs/index.d.ts.map +1 -1
  20. package/dist/cjs/index.js +48 -15
  21. package/dist/cjs/index.js.map +1 -1
  22. package/dist/cjs/iti.d.ts +33 -0
  23. package/dist/cjs/iti.d.ts.map +1 -0
  24. package/dist/cjs/iti.js +42 -0
  25. package/dist/cjs/iti.js.map +1 -0
  26. package/dist/cjs/package.json +1 -0
  27. package/dist/cjs/policy.d.ts +13 -0
  28. package/dist/cjs/policy.d.ts.map +1 -0
  29. package/dist/cjs/policy.js +18 -0
  30. package/dist/cjs/policy.js.map +1 -0
  31. package/dist/cjs/replay.d.ts +26 -0
  32. package/dist/cjs/replay.d.ts.map +1 -0
  33. package/dist/cjs/replay.js +39 -0
  34. package/dist/cjs/replay.js.map +1 -0
  35. package/dist/cjs/trust_root.d.ts +13 -0
  36. package/dist/cjs/trust_root.d.ts.map +1 -0
  37. package/dist/cjs/trust_root.js +18 -0
  38. package/dist/cjs/trust_root.js.map +1 -0
  39. package/dist/cjs/types.d.ts +195 -0
  40. package/dist/cjs/types.d.ts.map +1 -0
  41. package/dist/cjs/types.js +9 -0
  42. package/dist/cjs/types.js.map +1 -0
  43. package/dist/cjs/verify.d.ts +191 -0
  44. package/dist/cjs/verify.d.ts.map +1 -0
  45. package/dist/cjs/verify.js +615 -0
  46. package/dist/cjs/verify.js.map +1 -0
  47. package/dist/esm/attestation.d.ts +29 -0
  48. package/dist/esm/attestation.d.ts.map +1 -0
  49. package/dist/esm/attestation.js +37 -0
  50. package/dist/esm/attestation.js.map +1 -0
  51. package/dist/esm/canonical.d.ts +51 -0
  52. package/dist/esm/canonical.d.ts.map +1 -0
  53. package/dist/esm/canonical.js +157 -0
  54. package/dist/esm/canonical.js.map +1 -0
  55. package/dist/esm/decision-web.d.ts +29 -0
  56. package/dist/esm/decision-web.d.ts.map +1 -0
  57. package/dist/esm/decision-web.js +312 -0
  58. package/dist/esm/decision-web.js.map +1 -0
  59. package/dist/esm/decision.d.ts +62 -0
  60. package/dist/esm/decision.d.ts.map +1 -0
  61. package/dist/esm/decision.js +314 -0
  62. package/dist/esm/decision.js.map +1 -0
  63. package/dist/esm/index.d.ts +31 -3
  64. package/dist/esm/index.d.ts.map +1 -1
  65. package/dist/esm/index.js +31 -2
  66. package/dist/esm/index.js.map +1 -1
  67. package/dist/esm/iti.d.ts +33 -0
  68. package/dist/esm/iti.d.ts.map +1 -0
  69. package/dist/esm/iti.js +38 -0
  70. package/dist/esm/iti.js.map +1 -0
  71. package/dist/esm/package.json +1 -0
  72. package/dist/esm/policy.d.ts +13 -0
  73. package/dist/esm/policy.d.ts.map +1 -0
  74. package/dist/esm/policy.js +15 -0
  75. package/dist/esm/policy.js.map +1 -0
  76. package/dist/esm/replay.d.ts +26 -0
  77. package/dist/esm/replay.d.ts.map +1 -0
  78. package/dist/esm/replay.js +34 -0
  79. package/dist/esm/replay.js.map +1 -0
  80. package/dist/esm/trust_root.d.ts +13 -0
  81. package/dist/esm/trust_root.d.ts.map +1 -0
  82. package/dist/esm/trust_root.js +15 -0
  83. package/dist/esm/trust_root.js.map +1 -0
  84. package/dist/esm/types.d.ts +195 -0
  85. package/dist/esm/types.d.ts.map +1 -0
  86. package/dist/esm/types.js +8 -0
  87. package/dist/esm/types.js.map +1 -0
  88. package/dist/esm/verify.d.ts +191 -0
  89. package/dist/esm/verify.d.ts.map +1 -0
  90. package/dist/esm/verify.js +575 -0
  91. package/dist/esm/verify.js.map +1 -0
  92. package/package.json +46 -30
  93. package/src/attestation.ts +50 -0
  94. package/src/canonical.ts +138 -0
  95. package/src/decision-web.ts +324 -0
  96. package/src/decision.ts +339 -0
  97. package/src/index.ts +54 -91
  98. package/src/iti.ts +44 -0
  99. package/src/policy.ts +20 -0
  100. package/src/replay.ts +44 -0
  101. package/src/trust_root.ts +20 -0
  102. package/src/types.ts +215 -0
  103. package/src/verify.ts +630 -0
  104. package/LICENSE +0 -18
  105. package/dist/cjs/client.d.ts +0 -175
  106. package/dist/cjs/client.d.ts.map +0 -1
  107. package/dist/cjs/client.js +0 -896
  108. package/dist/cjs/client.js.map +0 -1
  109. package/dist/cjs/errors.d.ts +0 -57
  110. package/dist/cjs/errors.d.ts.map +0 -1
  111. package/dist/cjs/errors.js +0 -95
  112. package/dist/cjs/errors.js.map +0 -1
  113. package/dist/cjs/models.d.ts +0 -499
  114. package/dist/cjs/models.d.ts.map +0 -1
  115. package/dist/cjs/models.js +0 -3
  116. package/dist/cjs/models.js.map +0 -1
  117. package/dist/esm/client.d.ts +0 -175
  118. package/dist/esm/client.d.ts.map +0 -1
  119. package/dist/esm/client.js +0 -891
  120. package/dist/esm/client.js.map +0 -1
  121. package/dist/esm/errors.d.ts +0 -57
  122. package/dist/esm/errors.d.ts.map +0 -1
  123. package/dist/esm/errors.js +0 -82
  124. package/dist/esm/errors.js.map +0 -1
  125. package/dist/esm/models.d.ts +0 -499
  126. package/dist/esm/models.d.ts.map +0 -1
  127. package/dist/esm/models.js +0 -2
  128. package/dist/esm/models.js.map +0 -1
  129. package/src/client.ts +0 -1061
  130. package/src/errors.ts +0 -81
  131. package/src/models.ts +0 -581
package/README.md CHANGED
@@ -1,58 +1,63 @@
1
- # eve-ai-governance
1
+ # eve-governance (TypeScript)
2
2
 
3
- **EVE AI Core Governance SDK (Node/TypeScript)** deterministic AI decision
4
- enforcement in one API call, plus offline proof verification.
3
+ TypeScript SDK for offline cryptographic verification of EVE AI Core
4
+ governance artifacts.
5
+
6
+ > **Note:** This package provides the TypeScript API contract and type
7
+ > definitions. Implementation bodies are stubs; the Python SDK
8
+ > (`sdks/governance/`) contains the reference implementation.
9
+
10
+ ## Installation
5
11
 
6
12
  ```bash
7
- npm install eve-ai-governance
13
+ npm install eve-governance
8
14
  ```
9
15
 
10
- Zero-config, dependency-light, ships ESM + CJS + type declarations.
16
+ ## Usage
11
17
 
12
- ## Enforce a decision
18
+ ```typescript
19
+ import {
20
+ verifyDecisionCertificate,
21
+ verifyChain,
22
+ verifyItiSnapshot,
23
+ healthBand,
24
+ } from "eve-governance";
13
25
 
14
- ```ts
15
- import { GovernanceClient, RateLimitError, PaymentRequiredError } from 'eve-ai-governance';
26
+ // Verify a decision certificate
27
+ const result = await verifyDecisionCertificate(cert);
28
+ console.log(result.valid ? "✓ VERIFIED" : "✗ FAILED");
16
29
 
17
- const client = new GovernanceClient({ apiKey: 'eve_sk_...' });
30
+ // Health band
31
+ console.log(healthBand(87.5)); // "GOOD"
32
+ ```
18
33
 
19
- const result = await client.evaluate({
20
- request_id: 'req-001',
21
- tenant_id: 'bank_001',
22
- proposed_action: { type: 'loan_approval', amount: 250000 },
23
- model_output: { decision: 'approve', confidence: 0.91 },
24
- context: { credit_score: 580, debt_to_income: 0.52 },
25
- policy_set: 'lending_v1',
26
- });
27
- // result.decision.status -> "ALLOWED" | "BLOCKED" | "MODIFIED"
34
+ ## API
28
35
 
29
- // Billing / rate-limit metadata from the most recent call:
30
- client.subscriptionState; // 'active' | 'past_due' | ...
31
- client.rateLimit; // { limit, remaining } | { limit: null, ... }
32
- client.quotaWarning; // null | 'payment_past_due'
33
- ```
36
+ ### `verifyHmac(payload, signature, key)`
37
+ Verify an HMAC-SHA256 signature.
34
38
 
35
- Auth is `Authorization: Bearer eve_...`; the org/tenant is derived from the key
36
- server-side. See the [Response-Header Contract](../../docs/sdk/RESPONSE_HEADER_CONTRACT.md)
37
- for the full status-code and accessor reference (`RateLimitError` on 429,
38
- `PaymentRequiredError` on 402).
39
+ ### `verifyDecisionCertificate(certDict, options?)`
40
+ Verify a single EVE CoreGuard decision certificate.
39
41
 
40
- ## Verify a proof offline
42
+ ### `verifyBundle(bundlePath, options?)`
43
+ Verify a replay export bundle (ZIP or JSONL).
41
44
 
42
- `verifyProof` recomputes the canonical content hash and checks the HMAC-SHA256
43
- signature **locally** no network call. The canonicalization is byte-for-byte
44
- compatible with the Python SDKs (`json.dumps(sort_keys=True)`), so a proof signed
45
- by EVE verifies here and vice-versa. Tampering any field (including nested ones)
46
- fails; a wrong/empty signature returns `false` (never throws).
45
+ ### `verifyChain(events)`
46
+ Verify hash-chain integrity of a list of audit events.
47
47
 
48
- ```ts
49
- import { GovernanceClient } from 'eve-ai-governance';
48
+ ### `verifyItiSnapshot(snapshot, options?)`
49
+ Verify an ITI snapshot.
50
50
 
51
- const ok = GovernanceClient.verifyProof(proofBundle, sharedSigningKey); // boolean
52
- ```
51
+ ### `healthBand(compositeScore)`
52
+ Map a score (0–100) to a health band string.
53
+
54
+ ### `analyzeReplayChain(events)`
55
+ Analyze a replay chain and return structured metrics.
56
+
57
+ ## Types
53
58
 
54
- The same canonicalizer is exported as `canonicalizeForHash` for custom tooling.
59
+ See `src/types.ts` for all TypeScript interfaces.
55
60
 
56
61
  ## License
57
62
 
58
- Proprietary. See LICENSE.
63
+ Proprietary EVE NeuroSystems LLC
@@ -0,0 +1,29 @@
1
+ /**
2
+ * EVE Governance SDK — Attestation verification stubs (TypeScript).
3
+ */
4
+ import type { VerificationResult, VerifyOptions } from "./types.js";
5
+ /**
6
+ * Verify a deployment attestation / build provenance artifact.
7
+ *
8
+ * @param attestation - The attestation dict.
9
+ * @param options - Optional signing key override.
10
+ * @returns - Resolves to a `VerificationResult`.
11
+ */
12
+ export declare function verifyDeploymentAttestation(attestation: Record<string, unknown>, options?: VerifyOptions): Promise<VerificationResult>;
13
+ /**
14
+ * Verify a tenant trust certificate.
15
+ *
16
+ * @param cert - The trust certificate dict.
17
+ * @param options - Optional signing key override.
18
+ * @returns - Resolves to a `VerificationResult`.
19
+ */
20
+ export declare function verifyTrustCertificate(cert: Record<string, unknown>, options?: VerifyOptions): Promise<VerificationResult>;
21
+ /**
22
+ * Verify an enterprise onboarding bundle.
23
+ *
24
+ * @param bundle - The onboarding bundle dict.
25
+ * @param options - Optional signing key override.
26
+ * @returns - Resolves to a `VerificationResult`.
27
+ */
28
+ export declare function verifyOnboardingBundle(bundle: Record<string, unknown>, options?: VerifyOptions): Promise<VerificationResult>;
29
+ //# sourceMappingURL=attestation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.d.ts","sourceRoot":"","sources":["../../src/attestation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEpE;;;;;;GAMG;AACH,wBAAsB,2BAA2B,CAC/C,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACpC,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAG7B;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAG7B;AAED;;;;;;GAMG;AACH,wBAAsB,sBAAsB,CAC1C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,OAAO,CAAC,EAAE,aAAa,GACtB,OAAO,CAAC,kBAAkB,CAAC,CAG7B"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * EVE Governance SDK — Attestation verification stubs (TypeScript).
4
+ */
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.verifyDeploymentAttestation = verifyDeploymentAttestation;
7
+ exports.verifyTrustCertificate = verifyTrustCertificate;
8
+ exports.verifyOnboardingBundle = verifyOnboardingBundle;
9
+ /**
10
+ * Verify a deployment attestation / build provenance artifact.
11
+ *
12
+ * @param attestation - The attestation dict.
13
+ * @param options - Optional signing key override.
14
+ * @returns - Resolves to a `VerificationResult`.
15
+ */
16
+ async function verifyDeploymentAttestation(attestation, options) {
17
+ // TODO: implement
18
+ throw new Error("Not implemented");
19
+ }
20
+ /**
21
+ * Verify a tenant trust certificate.
22
+ *
23
+ * @param cert - The trust certificate dict.
24
+ * @param options - Optional signing key override.
25
+ * @returns - Resolves to a `VerificationResult`.
26
+ */
27
+ async function verifyTrustCertificate(cert, options) {
28
+ // TODO: implement
29
+ throw new Error("Not implemented");
30
+ }
31
+ /**
32
+ * Verify an enterprise onboarding bundle.
33
+ *
34
+ * @param bundle - The onboarding bundle dict.
35
+ * @param options - Optional signing key override.
36
+ * @returns - Resolves to a `VerificationResult`.
37
+ */
38
+ async function verifyOnboardingBundle(bundle, options) {
39
+ // TODO: implement
40
+ throw new Error("Not implemented");
41
+ }
42
+ //# sourceMappingURL=attestation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"attestation.js","sourceRoot":"","sources":["../../src/attestation.ts"],"names":[],"mappings":";AAAA;;GAEG;;AAWH,kEAMC;AASD,wDAMC;AASD,wDAMC;AA3CD;;;;;;GAMG;AACI,KAAK,UAAU,2BAA2B,CAC/C,WAAoC,EACpC,OAAuB;IAEvB,kBAAkB;IAClB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,sBAAsB,CAC1C,IAA6B,EAC7B,OAAuB;IAEvB,kBAAkB;IAClB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,sBAAsB,CAC1C,MAA+B,EAC/B,OAAuB;IAEvB,kBAAkB;IAClB,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * EVE Governance SDK — pure canonicalization primitives.
3
+ *
4
+ * ZERO runtime dependencies and ZERO platform APIs (no `node:crypto`, no
5
+ * `Buffer`) — safe to run in Node **and** in the browser. This is the single
6
+ * source of truth for the serialization used by every verifier
7
+ * (`verify.ts` = Node, `decision.ts` = Node asymmetric, `decision-web.ts` =
8
+ * browser/WebCrypto), so their canonical bytes cannot drift apart.
9
+ *
10
+ * Two serializations, matching the Python backend byte-for-byte:
11
+ * - COMPACT json.dumps(obj, sort_keys=True, separators=(",",":"))
12
+ * -> eve-request-v1 / eve-response-v1 preimage digests + HMAC certs
13
+ * - DEFAULT-SEP json.dumps(payload, sort_keys=True) (", " / ": ")
14
+ * -> eve-jsonc-v1 decision-record content hash
15
+ *
16
+ * Both use ensure_ascii=True (non-ASCII -> \uXXXX) and recursive key sorting by
17
+ * Unicode code point.
18
+ */
19
+ /**
20
+ * Compare two strings by Unicode code point (matching Python `sort_keys=True`),
21
+ * NOT by UTF-16 code unit (JS default `Array.sort`), which diverges for
22
+ * astral-plane keys.
23
+ */
24
+ export declare function compareCodePoints(a: string, b: string): number;
25
+ /** Deep-copy with all object keys recursively sorted; arrays keep order. */
26
+ export declare function sortKeys(obj: unknown): unknown;
27
+ /**
28
+ * Escape to match Python `json.dumps` default (`ensure_ascii=True`): standard
29
+ * short escapes, `\uXXXX` (lowercase hex) for every other control char and every
30
+ * non-ASCII UTF-16 code unit. `/` is not escaped. Iterating code units yields
31
+ * the surrogate halves Python emits for astral characters.
32
+ */
33
+ export declare function escapeString(s: string): string;
34
+ /**
35
+ * Format a number to match Python `json.dumps`. Integers emit without a decimal
36
+ * point; non-integers use JS shortest repr (agrees with Python for the decimal
37
+ * values in EVE evidence). See the canonicalization registry for the
38
+ * integer-valued-float cross-language constraint.
39
+ */
40
+ export declare function formatNumber(n: number): string;
41
+ /** Compact serialization of an ALREADY key-sorted value (separators ",",":"). */
42
+ export declare function serializeCompact(value: unknown): string;
43
+ /** Default-separator serialization of an ALREADY key-sorted value (", " / ": "). */
44
+ export declare function serializeDefaultSep(value: unknown): string;
45
+ /** Canonical compact JSON bytes of a payload (sorts keys, then compact). */
46
+ export declare function canonicalizeCompact(payload: Record<string, unknown>): string;
47
+ /** Canonical default-separator JSON bytes of a payload (sorts keys, then ", "/": "). */
48
+ export declare function canonicalizeDefaultSep(payload: Record<string, unknown>): string;
49
+ /** Constant-time-ish equality for two strings (no platform crypto needed). */
50
+ export declare function constantTimeEqual(a: string, b: string): boolean;
51
+ //# sourceMappingURL=canonical.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.d.ts","sourceRoot":"","sources":["../../src/canonical.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAU9D;AAED,4EAA4E;AAC5E,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAW9C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAqB9C;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAO9C;AAmBD,iFAAiF;AACjF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAEvD;AAED,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAE1D;AAED,4EAA4E;AAC5E,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAE5E;AAED,wFAAwF;AACxF,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAE/E;AAED,8EAA8E;AAC9E,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAK/D"}
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ /**
3
+ * EVE Governance SDK — pure canonicalization primitives.
4
+ *
5
+ * ZERO runtime dependencies and ZERO platform APIs (no `node:crypto`, no
6
+ * `Buffer`) — safe to run in Node **and** in the browser. This is the single
7
+ * source of truth for the serialization used by every verifier
8
+ * (`verify.ts` = Node, `decision.ts` = Node asymmetric, `decision-web.ts` =
9
+ * browser/WebCrypto), so their canonical bytes cannot drift apart.
10
+ *
11
+ * Two serializations, matching the Python backend byte-for-byte:
12
+ * - COMPACT json.dumps(obj, sort_keys=True, separators=(",",":"))
13
+ * -> eve-request-v1 / eve-response-v1 preimage digests + HMAC certs
14
+ * - DEFAULT-SEP json.dumps(payload, sort_keys=True) (", " / ": ")
15
+ * -> eve-jsonc-v1 decision-record content hash
16
+ *
17
+ * Both use ensure_ascii=True (non-ASCII -> \uXXXX) and recursive key sorting by
18
+ * Unicode code point.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.compareCodePoints = compareCodePoints;
22
+ exports.sortKeys = sortKeys;
23
+ exports.escapeString = escapeString;
24
+ exports.formatNumber = formatNumber;
25
+ exports.serializeCompact = serializeCompact;
26
+ exports.serializeDefaultSep = serializeDefaultSep;
27
+ exports.canonicalizeCompact = canonicalizeCompact;
28
+ exports.canonicalizeDefaultSep = canonicalizeDefaultSep;
29
+ exports.constantTimeEqual = constantTimeEqual;
30
+ /**
31
+ * Compare two strings by Unicode code point (matching Python `sort_keys=True`),
32
+ * NOT by UTF-16 code unit (JS default `Array.sort`), which diverges for
33
+ * astral-plane keys.
34
+ */
35
+ function compareCodePoints(a, b) {
36
+ const ia = Array.from(a);
37
+ const ib = Array.from(b);
38
+ const n = Math.min(ia.length, ib.length);
39
+ for (let i = 0; i < n; i += 1) {
40
+ const ca = ia[i].codePointAt(0);
41
+ const cb = ib[i].codePointAt(0);
42
+ if (ca !== cb)
43
+ return ca - cb;
44
+ }
45
+ return ia.length - ib.length;
46
+ }
47
+ /** Deep-copy with all object keys recursively sorted; arrays keep order. */
48
+ function sortKeys(obj) {
49
+ if (Array.isArray(obj))
50
+ return obj.map(sortKeys);
51
+ if (obj !== null && typeof obj === "object") {
52
+ const src = obj;
53
+ const sorted = {};
54
+ for (const key of Object.keys(src).sort(compareCodePoints)) {
55
+ sorted[key] = sortKeys(src[key]);
56
+ }
57
+ return sorted;
58
+ }
59
+ return obj;
60
+ }
61
+ /**
62
+ * Escape to match Python `json.dumps` default (`ensure_ascii=True`): standard
63
+ * short escapes, `\uXXXX` (lowercase hex) for every other control char and every
64
+ * non-ASCII UTF-16 code unit. `/` is not escaped. Iterating code units yields
65
+ * the surrogate halves Python emits for astral characters.
66
+ */
67
+ function escapeString(s) {
68
+ let out = '"';
69
+ for (let i = 0; i < s.length; i += 1) {
70
+ const code = s.charCodeAt(i);
71
+ switch (code) {
72
+ case 0x22:
73
+ out += '\\"';
74
+ break;
75
+ case 0x5c:
76
+ out += "\\\\";
77
+ break;
78
+ case 0x08:
79
+ out += "\\b";
80
+ break;
81
+ case 0x09:
82
+ out += "\\t";
83
+ break;
84
+ case 0x0a:
85
+ out += "\\n";
86
+ break;
87
+ case 0x0c:
88
+ out += "\\f";
89
+ break;
90
+ case 0x0d:
91
+ out += "\\r";
92
+ break;
93
+ default:
94
+ if (code < 0x20 || code > 0x7e) {
95
+ out += "\\u" + code.toString(16).padStart(4, "0");
96
+ }
97
+ else {
98
+ out += s[i];
99
+ }
100
+ }
101
+ }
102
+ return out + '"';
103
+ }
104
+ /**
105
+ * Format a number to match Python `json.dumps`. Integers emit without a decimal
106
+ * point; non-integers use JS shortest repr (agrees with Python for the decimal
107
+ * values in EVE evidence). See the canonicalization registry for the
108
+ * integer-valued-float cross-language constraint.
109
+ */
110
+ function formatNumber(n) {
111
+ if (!Number.isFinite(n)) {
112
+ if (Number.isNaN(n))
113
+ return "NaN";
114
+ return n > 0 ? "Infinity" : "-Infinity";
115
+ }
116
+ if (Number.isInteger(n))
117
+ return Object.is(n, -0) ? "0" : String(n);
118
+ return String(n);
119
+ }
120
+ function serializeWith(value, itemSep, kvSep) {
121
+ if (value === null || value === undefined)
122
+ return "null";
123
+ const t = typeof value;
124
+ if (t === "string")
125
+ return escapeString(value);
126
+ if (t === "number")
127
+ return formatNumber(value);
128
+ if (t === "boolean")
129
+ return value ? "true" : "false";
130
+ if (t === "bigint")
131
+ return value.toString();
132
+ if (Array.isArray(value))
133
+ return "[" + value.map((v) => serializeWith(v, itemSep, kvSep)).join(itemSep) + "]";
134
+ if (t === "object") {
135
+ const obj = value;
136
+ const parts = [];
137
+ for (const key of Object.keys(obj))
138
+ parts.push(escapeString(key) + kvSep + serializeWith(obj[key], itemSep, kvSep));
139
+ return "{" + parts.join(itemSep) + "}";
140
+ }
141
+ return "null";
142
+ }
143
+ /** Compact serialization of an ALREADY key-sorted value (separators ",",":"). */
144
+ function serializeCompact(value) {
145
+ return serializeWith(value, ",", ":");
146
+ }
147
+ /** Default-separator serialization of an ALREADY key-sorted value (", " / ": "). */
148
+ function serializeDefaultSep(value) {
149
+ return serializeWith(value, ", ", ": ");
150
+ }
151
+ /** Canonical compact JSON bytes of a payload (sorts keys, then compact). */
152
+ function canonicalizeCompact(payload) {
153
+ return serializeCompact(sortKeys(payload));
154
+ }
155
+ /** Canonical default-separator JSON bytes of a payload (sorts keys, then ", "/": "). */
156
+ function canonicalizeDefaultSep(payload) {
157
+ return serializeDefaultSep(sortKeys(payload));
158
+ }
159
+ /** Constant-time-ish equality for two strings (no platform crypto needed). */
160
+ function constantTimeEqual(a, b) {
161
+ if (a.length !== b.length)
162
+ return false;
163
+ let diff = 0;
164
+ for (let i = 0; i < a.length; i += 1)
165
+ diff |= a.charCodeAt(i) ^ b.charCodeAt(i);
166
+ return diff === 0;
167
+ }
168
+ //# sourceMappingURL=canonical.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canonical.js","sourceRoot":"","sources":["../../src/canonical.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * EVE Governance SDK — BROWSER decision-record verifier (WebCrypto).
3
+ *
4
+ * The browser/isomorphic counterpart of `decision.ts`. It verifies the
5
+ * asymmetric, independently-verifiable `eve.decision.v3` decision certificate
6
+ * (`ed25519-` / `ecdsa-p256-`) using **WebCrypto (`crypto.subtle`)** and the
7
+ * shared pure canonicalization in `canonical.ts` — so its bytes match the Node
8
+ * and Python verifiers exactly. No `node:*` imports; runs in the browser and in
9
+ * Node (>=20). Public key only — no shared secret.
10
+ *
11
+ * `verifyDecisionRecordWeb` is **async** (WebCrypto is promise-based). HMAC
12
+ * records are reported not-independently-verifiable and are NOT verified here
13
+ * (symmetric verification belongs on a trusted server, not the browser).
14
+ *
15
+ * Browser support note: WebCrypto Ed25519 requires a recent browser
16
+ * (Chrome/Edge 137+, Firefox 129+, Safari 17+) or Node >=20. ECDSA-P256 is
17
+ * universally supported. If the runtime lacks Ed25519, verification returns a
18
+ * clear `valid:false` reason rather than throwing.
19
+ */
20
+ import type { DecisionRecordVerificationResult } from "./types.js";
21
+ import type { VerifyDecisionRecordOptions } from "./decision.js";
22
+ /**
23
+ * Verify an EVE decision record (or `{decision_record, verification}` wrapper)
24
+ * in the browser with WebCrypto. Async; mirrors `verifyDecisionRecord` (Node).
25
+ * HMAC records are reported not-independently-verifiable (not verified here).
26
+ * Never throws — failures resolve to `{ valid: false, ... }`.
27
+ */
28
+ export declare function verifyDecisionRecordWeb(recordOrEvidence: Record<string, unknown>, options?: VerifyDecisionRecordOptions): Promise<DecisionRecordVerificationResult>;
29
+ //# sourceMappingURL=decision-web.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decision-web.d.ts","sourceRoot":"","sources":["../../src/decision-web.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAOH,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,YAAY,CAAC;AACnE,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AA8MjE;;;;;GAKG;AACH,wBAAsB,uBAAuB,CAC3C,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzC,OAAO,GAAE,2BAAgC,GACxC,OAAO,CAAC,gCAAgC,CAAC,CAkF3C"}