eve-ai-governance 0.2.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/LICENSE ADDED
@@ -0,0 +1,18 @@
1
+ EVE AI Core Governance SDK (JavaScript) — Proprietary License
2
+ Copyright (c) 2026 EVE NeuroSystems LLC. All rights reserved.
3
+
4
+ This software (the "Software") is the confidential and proprietary property of
5
+ EVE NeuroSystems LLC ("Licensor") and is licensed, not sold. Subject to a
6
+ separate written commercial or pilot agreement with Licensor, you may use the
7
+ Software solely to integrate with the EVE AI Core / EVE CoreGuard service.
8
+ Absent such an agreement, no rights are granted other than to evaluate it.
9
+
10
+ You may not redistribute, sublicense, sell, publish, reverse engineer, or create
11
+ derivative works except as permitted by a commercial agreement or applicable
12
+ law, nor remove proprietary notices.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND. IN NO EVENT SHALL
15
+ LICENSOR BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY ARISING FROM THE
16
+ SOFTWARE OR ITS USE.
17
+
18
+ For licensing inquiries: sdk@eveaicore.com
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # eve-ai-governance
2
+
3
+ **EVE AI Core Governance SDK (Node/TypeScript)** — deterministic AI decision
4
+ enforcement in one API call, plus offline proof verification.
5
+
6
+ ```bash
7
+ npm install eve-ai-governance
8
+ ```
9
+
10
+ Zero-config, dependency-light, ships ESM + CJS + type declarations.
11
+
12
+ ## Enforce a decision
13
+
14
+ ```ts
15
+ import { GovernanceClient, RateLimitError, PaymentRequiredError } from 'eve-ai-governance';
16
+
17
+ const client = new GovernanceClient({ apiKey: 'eve_sk_...' });
18
+
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"
28
+
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
+ ```
34
+
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
+
40
+ ## Verify a proof offline
41
+
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).
47
+
48
+ ```ts
49
+ import { GovernanceClient } from 'eve-ai-governance';
50
+
51
+ const ok = GovernanceClient.verifyProof(proofBundle, sharedSigningKey); // boolean
52
+ ```
53
+
54
+ The same canonicalizer is exported as `canonicalizeForHash` for custom tooling.
55
+
56
+ ## License
57
+
58
+ Proprietary. See LICENSE.
@@ -0,0 +1,175 @@
1
+ import type { GovernanceClientOptions, VerifyRequest, VerifyResult, BatchResult, CircuitBreakerStatus, HealthStatus, PipelineStats, FirewallResult, RedactionResult, SemanticResult, PolicyResult, PolicyDefinition, Policy, TurnAssessment, BudgetResult, WatermarkResult, CostResult, ComplianceReport, DecisionReplay, Webhook, TenantDashboard, DriftAssessment, VerificationResult, ReviewSubmission, ReviewTicket, GovernanceChain, ChainHop, ResidencyResult, TestCase, SimulationResult, EvaluateRequest, EvaluationResult, ProofBundle, AuditExport, ResponseMeta } from './models';
2
+ /**
3
+ * EVE AI Core Governance Client.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * const client = new GovernanceClient({ apiKey: 'eve_sk_...' });
8
+ *
9
+ * const result = await client.verify({
10
+ * aiOutput: 'The capital of France is Paris.',
11
+ * domain: 'factual',
12
+ * confidence: 0.9,
13
+ * });
14
+ *
15
+ * if (result.blocked) {
16
+ * console.log(`BLOCKED: ${result.veto.reason}`);
17
+ * } else {
18
+ * console.log(`PASSED — CRD: ${result.crd.toFixed(2)}`);
19
+ * }
20
+ * ```
21
+ */
22
+ export declare class GovernanceClient {
23
+ private baseUrl;
24
+ private apiKey;
25
+ private timeoutMs;
26
+ private maxRetries;
27
+ private raiseOnVeto;
28
+ private _lastResponseMeta;
29
+ constructor(opts: GovernanceClientOptions);
30
+ /** Full parsed metadata of the most recent response, or null before any call. */
31
+ get lastResponseMeta(): ResponseMeta | null;
32
+ /** Subscription state from the last call (e.g. 'active', 'past_due', 'restricted'). */
33
+ get subscriptionState(): string | null;
34
+ /** Access state from the last call (e.g. 'full_access', 'warning', 'read_only'). */
35
+ get accessState(): string | null;
36
+ /** Non-null when the account is in a billing warning (e.g. 'payment_past_due'). */
37
+ get quotaWarning(): string | null;
38
+ /** Seconds to wait before retrying, from the last 429 (else null). */
39
+ get retryAfter(): number | null;
40
+ /** Rate-limit budget from the last call: { limit, remaining }. */
41
+ get rateLimit(): {
42
+ limit: number | null;
43
+ remaining: number | null;
44
+ };
45
+ /**
46
+ * Run AI output through the 8-stage governance enforcement pipeline.
47
+ */
48
+ verify(req: VerifyRequest): Promise<VerifyResult>;
49
+ /**
50
+ * Verify up to 50 AI outputs in a single request.
51
+ */
52
+ verifyBatch(items: VerifyRequest[]): Promise<BatchResult>;
53
+ /** Get the current circuit breaker state. */
54
+ circuitBreaker(): Promise<CircuitBreakerStatus>;
55
+ /** Check pipeline health. */
56
+ health(): Promise<HealthStatus>;
57
+ /** Get aggregate pipeline statistics. */
58
+ stats(): Promise<PipelineStats>;
59
+ /** Scan input text through the prompt firewall. */
60
+ scanInput(text: string, sessionId?: string): Promise<FirewallResult>;
61
+ /** Redact personally identifiable information from text. */
62
+ redactPII(text: string): Promise<RedactionResult>;
63
+ /** Detect semantic attacks (jailbreak, injection, etc.). */
64
+ detectAttack(text: string): Promise<SemanticResult>;
65
+ /** Evaluate text against governance policies. */
66
+ evaluatePolicy(text: string, opts?: {
67
+ confidence?: number;
68
+ domain?: string;
69
+ tenantId?: string;
70
+ }): Promise<PolicyResult>;
71
+ /** List governance policies, optionally filtered by tenant. */
72
+ listPolicies(tenantId?: string): Promise<Policy[]>;
73
+ /** Add a new governance policy. Returns the policy ID. */
74
+ addPolicy(policy: PolicyDefinition): Promise<string>;
75
+ /** Assess cumulative risk across a multi-turn session. */
76
+ assessTurn(sessionId: string, message: string, riskScore?: number): Promise<TurnAssessment>;
77
+ /** Record output and check against the session's token budget. */
78
+ checkBudget(sessionId: string, responseText: string): Promise<BudgetResult>;
79
+ /** Verify a governance watermark on AI-generated content. */
80
+ verifyWatermark(watermarkId: string, text?: string): Promise<WatermarkResult>;
81
+ /** Record LLM usage costs and check budget compliance. */
82
+ recordCost(tenantId: string, model: string, inputTokens: number, outputTokens: number): Promise<CostResult>;
83
+ /** Generate a compliance report for a tenant against a framework. */
84
+ generateComplianceReport(tenantId: string, framework: string, periodDays?: number): Promise<ComplianceReport>;
85
+ /** Replay a specific governance decision by ID. */
86
+ replayDecision(decisionId: string): Promise<DecisionReplay>;
87
+ /** Query governance decisions with optional filters. */
88
+ queryDecisions(opts?: {
89
+ sessionId?: string;
90
+ vetoType?: string;
91
+ limit?: number;
92
+ }): Promise<DecisionReplay[]>;
93
+ /** Register a webhook to receive governance event notifications. */
94
+ registerWebhook(name: string, url: string, events: string[], format?: string): Promise<Webhook>;
95
+ /** List all registered webhooks. */
96
+ listWebhooks(): Promise<Webhook[]>;
97
+ /** Get the governance analytics dashboard for a tenant. */
98
+ getTenantDashboard(tenantId: string): Promise<TenantDashboard>;
99
+ /** Check for model output drift against baseline. */
100
+ checkDrift(modelId: string): Promise<DriftAssessment>;
101
+ /** Verify model supply chain integrity and provenance. */
102
+ verifyModel(modelId: string): Promise<VerificationResult>;
103
+ /** Submit a governance decision for human review. */
104
+ submitForReview(opts: ReviewSubmission): Promise<ReviewTicket>;
105
+ /** Get pending human review tickets. */
106
+ getPendingReviews(limit?: number): Promise<ReviewTicket[]>;
107
+ /** Start a new governance chain for multi-model interactions. */
108
+ startChain(initiator: string, purpose: string): Promise<GovernanceChain>;
109
+ /** Record a hop in a governance chain. */
110
+ recordHop(chainId: string, fromModel: string, toModel: string, crdScore: number, vetoType: string): Promise<ChainHop>;
111
+ /** Check data residency compliance for a tenant and target region. */
112
+ checkResidency(text: string, tenantId: string, targetRegion: string): Promise<ResidencyResult>;
113
+ /** Run a policy simulation in a sandboxed environment. */
114
+ runSimulation(policies: PolicyDefinition[], testCases?: TestCase[]): Promise<SimulationResult>;
115
+ /** Evaluate a proposed AI decision against enterprise policy. */
116
+ evaluate(request: EvaluateRequest): Promise<EvaluationResult>;
117
+ /** List available policy sets on the server. */
118
+ listPolicySets(): Promise<{
119
+ policy_sets: string[];
120
+ }>;
121
+ /** Retrieve a cryptographic proof bundle for a governance decision. */
122
+ getProof(proofId: string): Promise<ProofBundle>;
123
+ /** Export governance decision records for compliance reporting. */
124
+ exportAudit(options?: {
125
+ since?: string;
126
+ actionType?: string;
127
+ decision?: string;
128
+ limit?: number;
129
+ }): Promise<AuditExport>;
130
+ /** Verify the integrity of the governance proof hash chain. */
131
+ verifyChain(): Promise<{
132
+ total_records: number;
133
+ chain_valid: boolean;
134
+ chain_message: string;
135
+ }>;
136
+ /**
137
+ * Verify a proof bundle's integrity locally (no server call).
138
+ * Requires the signing key used by the server.
139
+ *
140
+ * Canonicalization target: the EVE backend / Python SDK compute the proof's
141
+ * content hash as `sha256(json.dumps(payload, sort_keys=True))` — see
142
+ * `sdks/coreguard/eve_coreguard/client.py::verify_proof_offline` (which
143
+ * verifies these IDENTICAL flat proof bundles) and
144
+ * `sdks/proof/eve_proof/verify.py::recompute_content_hash`. To verify a
145
+ * server-issued proof, this MUST reproduce Python's `json.dumps(...,
146
+ * sort_keys=True)` output BYTE-FOR-BYTE: keys sorted at every depth, the
147
+ * `", "` / `": "` separators (spaces after comma/colon), and `ensure_ascii`
148
+ * escaping (every non-ASCII code unit → `\uXXXX`, surrogate pairs included).
149
+ * The signature is then `HMAC-SHA256(signing_key, content_hash)` (hex).
150
+ * @see canonicalizeForHash
151
+ */
152
+ static verifyProof(proof: ProofBundle, signingKey: string): boolean;
153
+ private _request;
154
+ private _get;
155
+ private _post;
156
+ private _maybeThrow;
157
+ }
158
+ /**
159
+ * Deterministic, recursive canonical JSON serializer matching Python's
160
+ * `json.dumps(value, sort_keys=True)` byte-for-byte:
161
+ * - object keys sorted by code point at EVERY depth (recurses into nested
162
+ * objects AND arrays; arrays keep their element order),
163
+ * - `", "` and `": "` separators (a space after each comma and colon),
164
+ * - `ensure_ascii` escaping for all non-ASCII characters.
165
+ *
166
+ * Primitives (string/number/boolean/null) delegate to JSON.stringify, whose
167
+ * number formatting and control/quote escaping match Python for the integer
168
+ * and finite-decimal values proof bundles carry. (Exotic floats — e.g. 1e21 —
169
+ * could differ from Python's repr, but proofs use plain ints/decimals.)
170
+ * `undefined` and functions are dropped from objects and rendered as `null`
171
+ * inside arrays, mirroring JSON.stringify; non-finite numbers become `null`.
172
+ */
173
+ export declare function canonicalizeForHash(value: unknown): string;
174
+ export default GovernanceClient;
175
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/client.ts"],"names":[],"mappings":"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"}