@aaes-ai/govern-sdk 0.0.0-stage → 0.1.3

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 ADDED
@@ -0,0 +1,35 @@
1
+ # Changelog
2
+
3
+ ## 0.1.3 candidate
4
+
5
+ - The package name is `@aaes-ai/govern-sdk`. npm still lists `@aaes-ai/sdk` through 0.1.2 until the rename release.
6
+ - Minor-unit amounts above `Number.MAX_SAFE_INTEGER` are refused before sending, since the caller's exact amount may already be lost as a double.
7
+ - A daemon-published spend cap (`spend_cap_minor`, federated `spend_cap.minor`) must be a nonnegative safe integer and `latency_added_ms` a finite nonnegative number; malformed values raise `AaesError` instead of being coerced, matching the Python and Go clients. An omitted cap still reads as `0`.
8
+
9
+ ## 0.1.2
10
+
11
+ - Packaging/metadata-only patch: the registry description states the canonical product positioning (AI governance platform for the action layer: permissions, approvals by authorized persons, spending limits on routed actions, sealed decision record), keywords added for registry search, the homepage points to aaes.ai/developers/sdks.html, and the README opens with the product definition. No functional changes; the shipped code is unchanged.
12
+
13
+ ## 0.1.1
14
+
15
+ - Packaging-only patch, published through the sdk-publish.yml npm trusted publisher with provenance. No functional changes; the shipped files are unchanged apart from the version field.
16
+ - Verified the 0.1.0 tarball already ships `README.md` (extracted by the registry), so no packaging change was required for npm's README rendering.
17
+
18
+ ## 0.1.0 — candidate
19
+
20
+ - Shared concurrent entitlement reads and prevented pre-refresh requests from replacing refreshed discovery data.
21
+ - Forwarded optional caller-declared provenance on brokered requests so the daemon can apply the same risk rules as action requests.
22
+
23
+ - Added bounded work, approval, entitlement and receipt reads.
24
+ - Added agent-manager card reads/decisions, with explicit decision binding.
25
+ - Added separate person-only access revocation client.
26
+ - Preserved daemon-derived identity, fixed destinations, effect-key safeguards and redacted federated material.
27
+ - Added native package consumer tests and release policy; TypeScript declarations and Python PEP 561 metadata.
28
+ - README method list now advertises the complete read and card surface; every advertised method is covered by the package tests.
29
+
30
+ - Reported deferred decisions instead of hiding them, and added resume across the three SDKs (Go `Resume`, Python `resume`, TypeScript `resume`): a deferred action is resubmitted unchanged under the same effect key via POST /v1/action/resume.
31
+ - Added brokered resume (Go `ResumeBrokered`, Python `resume_brokered`, TypeScript `resumeBrokered`): a standing brokered deferral is revalidated and executed through the connector via POST /v1/brokered/resume, and a brokered resume never reports a grant without a confirmed execution as success.
32
+ - Mapped a 404 from the resume routes to a refusal carrying the daemon's reason verbatim, falling back to the canned no-deferral sentence only when the 404 body states none; a missing deferral is answered without extra advice fetches, and decode errors name the resume route.
33
+ - The TypeScript package publishes under the `@aaes-ai` npm scope (`@aaes-ai/sdk`), matching the GitHub organization and the Go module path; `@aaes/sdk` was never published, so the rename carried no migration cost.
34
+
35
+ This entry describes the source candidate, not a published registry release.
package/README.md CHANGED
@@ -1,3 +1,55 @@
1
- # Temporary Holding Version
1
+ # AAES TypeScript / JavaScript SDK
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ AAES (Autonomous Agentic Enterprise Systems) is an AI governance platform for the action layer: permissions, approvals by authorized persons, and spending limits on requests routed through it, with a sealed record of each completed decision. This package is its TypeScript/JavaScript client.
4
+
5
+ ES module package `@aaes-ai/govern-sdk`, dependency-free runtime, with complete public TypeScript declarations and wire response types. Node 18+.
6
+
7
+ ```bash
8
+ npm install ./sdk/typescript # install local candidate
9
+ node sdk/typescript/aaes.test.mjs # node:test, nothing to install
10
+ ```
11
+
12
+ These examples require SDK access, a running AAES daemon, and a token issued by
13
+ your deployment operator. Set `AAES_ENDPOINT` and `AAES_TOKEN` first. The request
14
+ reads permitted capabilities; it does not execute an agent action.
15
+
16
+ ```js
17
+ import { Client } from "@aaes-ai/govern-sdk";
18
+
19
+ try {
20
+ const result = await Client.fromEnv().capabilities();
21
+ console.log(`${result.capabilities.length} permitted capabilities`);
22
+ } catch (error) {
23
+ console.error(String(error));
24
+ process.exitCode = 1;
25
+ }
26
+ ```
27
+
28
+ Methods: `capabilities`, `catalogue`, `health`, `action`, `brokered`,
29
+ `resume`, `resumeBrokered`, `presentGrant`, `requestAccess`, `accessRequest`, `observe`, `refresh`,
30
+ `federate`, the bounded reads `listTask`, `task`, `listApprovals`,
31
+ `approval`, `listEntitlements`, `listReceipts`, `receipt`, the
32
+ agent-manager card reads `managerCards` and `decideManagerCard`, the
33
+ person-only operator client's `revokeAccessRequest`, and the exported
34
+ `verifyHint(exportPath, publicKeyPath)`. Every method above is covered by
35
+ this package's tests (`aaes.test.mjs`, `resume.test.mjs`, `read.test.mjs`, `federation.test.mjs`).
36
+
37
+ What it deliberately does not do: `action()`, `requestAccess()` and
38
+ `observe()` refuse any key they do not document, so `url`, `method`,
39
+ `headers`, `credential`, `token`, `tenantId` and `actorId` cannot be
40
+ smuggled in; the payload is checked against the field names the daemon refuses;
41
+ tenant and actor come from `GET /v1/capabilities`; receipts are the daemon's
42
+ bytes and are verified offline with `aaesctl verify`; a mutating call is
43
+ retried only on opt-in, only after a 503, and only under the same effect key.
44
+
45
+ Full guide: [docs/guides/INTEGRATION.md](../../docs/guides/INTEGRATION.md).
46
+
47
+ A 503 response does not prove that the provider performed no action. Repeat only the identical request with its original effect key; never change the key to force a retry. The daemon retains the reservation and dispatch claim for uncertain outcomes and may answer the repeat with 409. It permits another dispatch only after proving that the previous attempt was never dispatched.
48
+
49
+ ## Candidate package and expanded contract
50
+
51
+ See [SDK release policy](../RELEASE.md) and [complete operation/scope table](../CONTRACT.md). npm lists `@aaes-ai/sdk` through 0.1.2. This tree's package name is `@aaes-ai/govern-sdk`.
52
+
53
+ Endpoint transport: bearer credentials require HTTPS. HTTP is accepted only
54
+ for explicit loopback addresses (`localhost`, `127.0.0.0/8`, or `::1`); DNS
55
+ resolution is never used to authorize plaintext transport.
package/aaes.d.mts ADDED
@@ -0,0 +1,180 @@
1
+ import type * as Wire from './wire.js';
2
+ export type { Task, TaskPage, Approval, ApprovalPage, EntitlementPage, ReceiptView, ReceiptPage, PageInfo, ManagerCard, ManagerCardsResponse, ManagerCardDecisionRecorded } from './wire.js';
3
+ export const ENDPOINT_ENV: 'AAES_ENDPOINT';
4
+ export const TOKEN_ENV: 'AAES_TOKEN';
5
+ export const EFFECT_DENIED: 0;
6
+ export const EFFECT_MINTED_UNUSED: 1;
7
+ export const EFFECT_EXECUTED: 2;
8
+ export const EFFECT_AUTHORIZED: 3;
9
+ export const EFFECT_DEFERRED: 4;
10
+ export class AaesError extends Error {}
11
+ export class CallerRouteError extends AaesError {}
12
+ export type JSONValue = string | number | boolean | null | JSONValue[] | { [key: string]: JSONValue };
13
+ export type Payload = { [key: string]: JSONValue };
14
+ export class RetryPolicy {
15
+ constructor(options?: { maxAttempts?: number; baseDelayMs?: number });
16
+ maxAttempts: number; baseDelayMs: number;
17
+ static default(): RetryPolicy;
18
+ attempts(identified: boolean, answer503: boolean): number;
19
+ delay(attempt: number): number;
20
+ }
21
+ export class Refusal {
22
+ constructor(status: number, reason: string, advice?: string[], retryable?: boolean);
23
+ status: number; reason: string; advice: string[]; retryable: boolean;
24
+ smallestChange(): string; toString(): string;
25
+ }
26
+ export interface Grant {
27
+ grantId: string; actorId: string; tenantId: string; capability: string; tier: string;
28
+ taskId: string; issuedAt: string; expiresAt: string; ttlSeconds: number;
29
+ spendCapMinor: number; spendCapCurrency: string; nonTransferable: boolean;
30
+ budgetGrantId: string; issuer: string; signature: string;
31
+ }
32
+ export interface GrantPresent {
33
+ grantId: string; actorId: string; tenantId: string; capability: string; tier: string;
34
+ taskId: string; issuedAt: string; expiresAt: string; spendCapMinor: number; spendCapCurrency: string;
35
+ }
36
+ export interface Receipt {
37
+ receiptId: string; intentId: string; tenantId: string; taskId: string; approvalId: string;
38
+ custody: string; grantId: string; effectId: string; effect: string; recordHash: string;
39
+ issuedAt: string; effectClass: number; railConfirmed: boolean; confirmedAt: string;
40
+ reportedBy: string; reportedAt: string; observedAt: string; reportedOutcome: string;
41
+ note: string; receiptHash: string; policyBundleHash: string; inputHash: string; engineVersion: string;
42
+ }
43
+ export class Decision {
44
+ constructor(fields?: Partial<Omit<Decision, 'ok'>>);
45
+ allowed: boolean; deferred: boolean; reason: string; intentId: string; grant: Grant | null; receipt: Receipt | null;
46
+ latencyAddedMs: number; refusal: Refusal | null; readonly ok: boolean;
47
+ }
48
+ export interface ExternalRef {
49
+ registry: string; kind: string; value: string; source: "registered";
50
+ }
51
+ export interface Action {
52
+ capability: string; action?: string; taskId?: string; callerTaskId?: string; effectKeyStep?: string;
53
+ amountMinor?: number; amountCurrency?: string; grantTtlMs?: number; correlationId?: string; parentIntentId?: string;
54
+ contractId?: string; model?: string; provenanceStatus?: "asserted" | "unknown"; externalRefs?: ExternalRef[];
55
+ payload?: Payload | null;
56
+ }
57
+ export interface BrokeredResult { decision: Decision; outcome: Partial<Wire.Outcome> }
58
+ export interface Capability {
59
+ capabilityId: string; version: string; pinned: boolean; kind: string; owner: string;
60
+ riskTier: string; actions: string[]; resourceId: string; dataClass: string; custody: string;
61
+ enforcement: string; taskId: string; callerTaskId: string; expiresAt: string | null;
62
+ source: string; requestId: string; readonly name: string;
63
+ }
64
+ export interface Entitlement {
65
+ tenantId: string; actorId: string; capabilities: Capability[]; find(spelling: string): Capability | null;
66
+ }
67
+ export interface CataloguePolicy {
68
+ policyId: string; label: string; required: number; minHumans: number; classes: string[]; authority: string;
69
+ }
70
+ export interface CatalogueEntry {
71
+ capabilityId: string; version: string; kind: string; owner: string; riskTier: string; actions: string[];
72
+ resourceId: string; dataClass: string; custody: string; policy: CataloguePolicy;
73
+ }
74
+ export interface Catalog {
75
+ tenantId: string; actorId: string; requestable: CatalogueEntry[]; find(spelling: string): CatalogueEntry | null;
76
+ }
77
+ export interface AccessAsk {
78
+ capability: string; actions?: string[]; resourceId?: string; surfaceResourceId?: string; teamId?: string;
79
+ dataClass?: string; tier?: string; budgetMinor?: number; budgetCurrency?: string; ttlSeconds?: number; taskId?: string;
80
+ justification?: string; duration?: string; reviewDays?: number; windowStart?: string; windowEnd?: string;
81
+ windowTimezone?: string;
82
+ }
83
+ export interface AccessAnswer {
84
+ requestId: string; state: string; needed: Partial<Wire.Quorum>; alreadyHeld: boolean; refusal: Refusal | null;
85
+ }
86
+ export interface AccessView {
87
+ requestId: string; state: string; needed: Partial<Wire.Quorum>; tenantId: string; actorId: string;
88
+ capability: string; actions: string[]; resourceId: string; surfaceResourceId: string; teamId: string;
89
+ dataClass: string; tier: string; budgetMinor: number; budgetCurrency: string; ttlSeconds: number;
90
+ taskId: string; justification: string; duration: string; reviewTtlSeconds: number;
91
+ windowStart: string; windowEnd: string; windowTimezone: string; reviewRequired: boolean;
92
+ reviewedBy: string; reviewedAt: string | null; reviewed: boolean; approvalId: string;
93
+ approvals: Wire.AccessApprovalState[]; decidedBy: string[]; decidedAt: string | null;
94
+ expiresAt: string | null; createdAt: string | null; reason: string;
95
+ }
96
+ export interface Observation { intentId: string; effectId?: string; outcome?: string; observedAt?: string; note?: string }
97
+ export interface ObserveResult {
98
+ intentId: string; receipt: Receipt | null; label: string; enforcement: string;
99
+ countsTowardCoverage: boolean; refusal: Refusal | null;
100
+ }
101
+ export interface FederateRequest {
102
+ capability: string; action?: string; taskId: string; effectKeyStep: string; amountMinor?: number;
103
+ amountCurrency?: string; grantTtlMs?: number; rotate?: boolean; correlationId?: string;
104
+ }
105
+ export class FederatedInstructions {
106
+ constructor(fields?: Partial<FederatedInstructions>);
107
+ backend: string; method: string; url: string; headers: Record<string, string>; form: Record<string, string>;
108
+ json: Record<string, unknown>; subjectTokenIn: string; subjectTokenField: string; subjectTokenType: string;
109
+ durationSeconds: number; documentation: string; notBuilt: string[]; notes: string[];
110
+ toString(): string;
111
+ toJSON(): { backend: string; method: string; url: string; subjectTokenField: string };
112
+ }
113
+ export class FederatedMaterial {
114
+ constructor(fields?: Partial<FederatedMaterial>);
115
+ kind: string; credential: Uint8Array; instructions: FederatedInstructions | null; expiresAt: string; audience: string;
116
+ toString(): string; toJSON(): { kind: string; redacted: true; expiresAt: string; audience: string };
117
+ }
118
+ export interface FederatedLocator { capability: string; endpoint: string; method: string; authority: string; resourceId: string }
119
+ export interface FederatedRecord { intentId: string; mode: string; payloadSeen: boolean; markerReceiptHash: string; receiptId: string }
120
+ export interface FederatedScope { capability: string; actions: string[]; resourceId: string; dataClass: string; tier: string; spendCapMinor: number; spendCapCurrency: string; scopeKey: string }
121
+ export class FederatedGrant {
122
+ constructor(fields?: Partial<FederatedGrant>);
123
+ federationId: string; intentId: string; decisionGrantId: string; tenantId: string; actorId: string;
124
+ capability: string; capabilityVersion: string; actions: string[]; resourceId: string; taskId: string;
125
+ dataClass: string; tier: string; spendCapMinor: number; spendCapCurrency: string; scopeKey: string; backend: string;
126
+ locator: FederatedLocator; issuedAt: string; expiresAt: string; ttlSeconds: number;
127
+ material: FederatedMaterial; record: FederatedRecord;
128
+ scope(): FederatedScope; toString(): string;
129
+ toJSON(): { federation_id: string; intent_id: string; decision_grant_id: string; tenant_id: string;
130
+ actor_id: string; capability: string; actions: string[]; resource_id: string; task_id: string;
131
+ data_class: string; tier: string; scope_key: string; backend: string; locator: FederatedLocator;
132
+ issued_at: string; expires_at: string; ttl_seconds: number; material: ReturnType<FederatedMaterial['toJSON']>; record: FederatedRecord };
133
+ }
134
+ export type FederatedResult =
135
+ | { ok: true; allowed: true; reason: string; grant: FederatedGrant; refusal: null }
136
+ | { ok: false; allowed: false; reason: string; grant: null; refusal: Refusal };
137
+ export interface ClientOptions {
138
+ endpoint?: string; token?: string; retries?: RetryPolicy; timeoutMs?: number; fetchImpl?: typeof fetch;
139
+ }
140
+ export interface PageFilters { limit?: number; cursor?: string }
141
+ export interface TimeFilters extends PageFilters { since?: string; until?: string }
142
+ export interface TaskFilters extends TimeFilters { state?: string; sponsor?: string; assignee?: string; overdue?: boolean }
143
+ export interface ApprovalFilters extends TimeFilters { intentId?: string; taskId?: string; state?: 'pending' | 'all' }
144
+ export interface EntitlementFilters extends PageFilters { actorId?: string; capability?: string; state?: 'all' | 'usable' | 'expired' | 'revoked' }
145
+ export interface ReceiptFilters extends TimeFilters { intentId?: string; taskId?: string; effectClass?: 'denied' | 'minted_unused' | 'authorized' | 'executed'; custody?: string }
146
+ export interface ManagerCardDecision { cardId: string; approvalId: string; payloadHash: string; policyId?: string; grant: boolean; reason?: string }
147
+ export class Client {
148
+ constructor(options?: ClientOptions);
149
+ static fromEnv(options?: ClientOptions): Client;
150
+ refresh(): void;
151
+ entitlement(): Promise<Entitlement>;
152
+ capabilities(): Promise<Entitlement>;
153
+ catalog(): Promise<Catalog>;
154
+ health(): Promise<{ healthz: Wire.HealthResponse; readyz: Wire.ReadinessResponse; ready: boolean; reason: string }>;
155
+ action(action: Action): Promise<Decision>;
156
+ resume(action: Action): Promise<Decision>;
157
+ brokered(action: Action): Promise<BrokeredResult>;
158
+ resumeBrokered(action: Action): Promise<BrokeredResult>;
159
+ presentGrant(grantId: string): Promise<GrantPresent>;
160
+ federate(request: FederateRequest): Promise<FederatedResult>;
161
+ requestAccess(ask: AccessAsk): Promise<AccessAnswer>;
162
+ accessRequest(requestId: string): Promise<AccessView>;
163
+ observe(report: Observation): Promise<ObserveResult>;
164
+ listTask(filters?: TaskFilters): Promise<Wire.TaskPage>;
165
+ task(id: string): Promise<Wire.Task>;
166
+ listApprovals(filters?: ApprovalFilters): Promise<Wire.ApprovalPage>;
167
+ approval(id: string): Promise<Wire.Approval>;
168
+ listEntitlements(filters?: EntitlementFilters): Promise<Wire.EntitlementPage>;
169
+ listReceipts(filters?: ReceiptFilters): Promise<Wire.ReceiptPage>;
170
+ receipt(id: string): Promise<Wire.ReceiptView>;
171
+ managerCards(): Promise<Wire.ManagerCardsResponse>;
172
+ decideManagerCard(decision: ManagerCardDecision): Promise<Wire.ManagerCardDecisionRecorded>;
173
+ }
174
+ /** Requires a separately issued person token. The daemon authorizes each call. */
175
+ export class OperatorClient extends Client {
176
+ static fromEnv(options?: ClientOptions): OperatorClient;
177
+ revokeAccessRequest(id: string, options?: { reason?: string }): Promise<AccessView>;
178
+ }
179
+ export function guardPayload(payload?: Payload | null): Payload | null;
180
+ export function verifyHint(exportPath: string, publicKeyPath?: string): string;