@auctra/sdk 0.3.4 → 0.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.
package/src/index.ts CHANGED
@@ -1,4 +1,6 @@
1
- export const AUCTRA_SDK_VERSION = "0.3.3";
1
+ import { createHash, createPublicKey, verify as cryptoVerify, type KeyObject } from "node:crypto";
2
+
3
+ export const AUCTRA_SDK_VERSION = "0.6.0";
2
4
 
3
5
  export type AgentEnvironment = "dev" | "staging" | "production";
4
6
  export type AuthorityLevel = "low" | "medium" | "high" | "critical";
@@ -33,10 +35,18 @@ export type EvaluateActionResponse = {
33
35
  risk_score: number;
34
36
  reason: string;
35
37
  delegation_id: string | null;
38
+ authority_id: string | null;
36
39
  delegator: string | null;
37
40
  sponsor: string;
38
41
  matched_policies: string[];
39
42
  action_request_id: string;
43
+ evidence: DecisionEvidence;
44
+ evidence_payload: DecisionEvidencePayload;
45
+ protocol?: {
46
+ version: string;
47
+ action?: Record<string, unknown>;
48
+ decision?: Record<string, unknown>;
49
+ };
40
50
  intelligence?: {
41
51
  authority_valid: boolean;
42
52
  root_intent_valid: boolean;
@@ -107,6 +117,10 @@ export type Delegation = {
107
117
  valid_until: string;
108
118
  status: "active" | "revoked" | "expired";
109
119
  is_active: boolean;
120
+ mandate?: MandateEvidence | null;
121
+ mandate_payload?: MandatePayload | null;
122
+ evidence?: DecisionEvidence | null;
123
+ evidence_payload?: DecisionEvidencePayload | null;
110
124
  created_at: string;
111
125
  };
112
126
 
@@ -119,6 +133,10 @@ export type CreateDelegationInput = {
119
133
  environment?: AgentEnvironment;
120
134
  currency?: string;
121
135
  delegatorUserId?: string;
136
+ /** Parent authority/delegation id for subset-constrained delegation chains. */
137
+ parentAuthorityId?: string;
138
+ parentDelegationId?: string;
139
+ maxDelegationDepth?: number;
122
140
  maxActionsPerWindow?: {
123
141
  count: number;
124
142
  windowSeconds: number;
@@ -130,6 +148,49 @@ export type CreateDelegationInput = {
130
148
  };
131
149
  };
132
150
 
151
+ export type AuthoritySummary = {
152
+ id: string;
153
+ protocol_version: string;
154
+ status: string;
155
+ payload_hash: string;
156
+ signed: boolean;
157
+ parent_authority_id: string | null;
158
+ capabilities: unknown;
159
+ };
160
+
161
+ export type IssueAuthorityInput = {
162
+ /** Subject agent id */
163
+ subject: string;
164
+ capabilities: string[];
165
+ expiresAt: string;
166
+ constraints?: {
167
+ maxAmount?: number;
168
+ currency?: string;
169
+ maxCount?: number;
170
+ environment?: AgentEnvironment;
171
+ };
172
+ delegation?: {
173
+ allowed?: boolean;
174
+ maxDepth?: number;
175
+ };
176
+ issuer?: string;
177
+ delegatorUserId?: string;
178
+ maxActionsPerWindow?: {
179
+ count: number;
180
+ windowSeconds: number;
181
+ actionType?: string;
182
+ };
183
+ maxAmountPerWindow?: {
184
+ amount: number;
185
+ windowSeconds: number;
186
+ };
187
+ };
188
+
189
+ export type DelegateAuthorityInput = IssueAuthorityInput & {
190
+ /** Parent authority id — child must be a subset of parent */
191
+ parent: string;
192
+ };
193
+
133
194
  export type ActionRequest = {
134
195
  id: string;
135
196
  agent_name: string;
@@ -338,6 +399,59 @@ export type PolicySimulation = {
338
399
  }>;
339
400
  };
340
401
 
402
+ export type MandateEvidence =
403
+ | {
404
+ format: "auctra-mandate.v0.1";
405
+ payload_hash: string;
406
+ signed: false;
407
+ }
408
+ | {
409
+ format: "auctra-mandate.v0.1";
410
+ signed: true;
411
+ payload_hash: string;
412
+ payload: Record<string, unknown>;
413
+ signature: { alg: "Ed25519"; key_id: string; value: string };
414
+ };
415
+
416
+ export type MandatePayload = Record<string, unknown>;
417
+
418
+ export type DecisionEvidencePayload = Record<string, unknown>;
419
+
420
+ export type DecisionEvidence =
421
+ | {
422
+ format: "auctra-evidence.v0.1";
423
+ payload_hash: string;
424
+ signed: false;
425
+ }
426
+ | {
427
+ format: "auctra-evidence.v0.1";
428
+ signed: true;
429
+ payload_hash: string;
430
+ payload: Record<string, unknown>;
431
+ signature: { alg: "Ed25519"; key_id: string; value: string };
432
+ };
433
+
434
+ export type AuditChainVerification = {
435
+ valid: boolean;
436
+ total: number;
437
+ sealed_total: number;
438
+ legacy_unsealed_total: number;
439
+ events: Array<{
440
+ id: string;
441
+ hashValid: boolean;
442
+ linkValid: boolean;
443
+ sequenceValid: boolean;
444
+ valid: boolean;
445
+ legacy: boolean;
446
+ }>;
447
+ };
448
+
449
+ export type ArtifactVerification = {
450
+ valid: boolean;
451
+ hashValid: boolean;
452
+ signatureValid: boolean;
453
+ };
454
+
341
455
  export type AuditEvent = {
342
456
  id: string;
343
457
  event_type: string;
@@ -351,6 +465,10 @@ export type AuditEvent = {
351
465
  delegation_id: string | null;
352
466
  hash: string | null;
353
467
  previous_hash: string | null;
468
+ chain_index?: number;
469
+ mandate?: MandateEvidence | null;
470
+ evidence?: DecisionEvidence | null;
471
+ payload?: Record<string, unknown>;
354
472
  created_at: string;
355
473
  };
356
474
 
@@ -410,6 +528,91 @@ function wait(ms: number, signal?: AbortSignal) {
410
528
  });
411
529
  }
412
530
 
531
+ function canonicalizeJson(value: unknown): unknown {
532
+ if (Array.isArray(value)) return value.map(canonicalizeJson);
533
+ if (value && typeof value === "object" && !(value instanceof Date)) {
534
+ return Object.fromEntries(
535
+ Object.entries(value as Record<string, unknown>)
536
+ .filter(([, child]) => child !== undefined)
537
+ .sort(([left], [right]) => left.localeCompare(right))
538
+ .map(([key, child]) => [key, canonicalizeJson(child)]),
539
+ );
540
+ }
541
+ if (value instanceof Date) return value.toISOString();
542
+ return value;
543
+ }
544
+
545
+ function hashJson(value: unknown) {
546
+ return createHash("sha256")
547
+ .update(JSON.stringify(canonicalizeJson(value)))
548
+ .digest("hex");
549
+ }
550
+
551
+ function verifyEd25519(input: {
552
+ payload: unknown;
553
+ signature: { alg: "Ed25519"; value: string };
554
+ publicKeyPem?: string | KeyObject;
555
+ }) {
556
+ if (!input.publicKeyPem) return false;
557
+ if (input.signature.alg !== "Ed25519") return false;
558
+ return cryptoVerify(
559
+ null,
560
+ Buffer.from(JSON.stringify(canonicalizeJson(input.payload))),
561
+ typeof input.publicKeyPem === "string"
562
+ ? createPublicKey(input.publicKeyPem)
563
+ : input.publicKeyPem,
564
+ Buffer.from(input.signature.value, "base64url"),
565
+ );
566
+ }
567
+
568
+ export function verifyMandateArtifact(input: {
569
+ payload: MandatePayload;
570
+ evidence: MandateEvidence;
571
+ publicKeyPem?: string | KeyObject;
572
+ }): ArtifactVerification {
573
+ const expectedHash = hashJson(input.payload);
574
+ if (input.evidence.format !== "auctra-mandate.v0.1") {
575
+ return { valid: false, hashValid: false, signatureValid: false };
576
+ }
577
+ if (!input.evidence.signed) {
578
+ const hashValid = input.evidence.payload_hash === expectedHash;
579
+ return { valid: hashValid, hashValid, signatureValid: false };
580
+ }
581
+ const hashValid = input.evidence.payload_hash === expectedHash;
582
+ const signatureValid =
583
+ hashValid &&
584
+ verifyEd25519({
585
+ payload: input.payload,
586
+ signature: input.evidence.signature,
587
+ publicKeyPem: input.publicKeyPem,
588
+ });
589
+ return { valid: hashValid && signatureValid, hashValid, signatureValid };
590
+ }
591
+
592
+ export function verifyDecisionArtifact(input: {
593
+ payload: DecisionEvidencePayload;
594
+ evidence: DecisionEvidence;
595
+ publicKeyPem?: string | KeyObject;
596
+ }): ArtifactVerification {
597
+ const expectedHash = hashJson(input.payload);
598
+ if (input.evidence.format !== "auctra-evidence.v0.1") {
599
+ return { valid: false, hashValid: false, signatureValid: false };
600
+ }
601
+ if (!input.evidence.signed) {
602
+ const hashValid = input.evidence.payload_hash === expectedHash;
603
+ return { valid: hashValid, hashValid, signatureValid: false };
604
+ }
605
+ const hashValid = input.evidence.payload_hash === expectedHash;
606
+ const signatureValid =
607
+ hashValid &&
608
+ verifyEd25519({
609
+ payload: input.payload,
610
+ signature: input.evidence.signature,
611
+ publicKeyPem: input.publicKeyPem,
612
+ });
613
+ return { valid: hashValid && signatureValid, hashValid, signatureValid };
614
+ }
615
+
413
616
  export class Auctra {
414
617
  private readonly apiKey: string;
415
618
  private readonly baseUrl: string;
@@ -500,14 +703,17 @@ export class Auctra {
500
703
  throw lastError;
501
704
  }
502
705
 
503
- async evaluateAction(
706
+ private async executeOrEvaluateAction(
504
707
  input: EvaluateActionInput,
505
- options: RequestOptions = {},
708
+ options: RequestOptions,
709
+ mode: "execute" | "evaluate",
506
710
  ): Promise<EvaluateActionResponse> {
507
- const idempotencyKey = options.idempotencyKey ?? crypto.randomUUID();
711
+ const idempotencyKey =
712
+ mode === "execute" ? (options.idempotencyKey ?? crypto.randomUUID()) : options.idempotencyKey;
713
+ const path = mode === "execute" ? "/v1/actions/execute" : "/v1/actions/evaluate";
508
714
  return this.request(
509
715
  "POST",
510
- "/v1/action-requests/evaluate",
716
+ path,
511
717
  {
512
718
  agent_id: input.agentId,
513
719
  action_type: input.actionType,
@@ -515,6 +721,7 @@ export class Auctra {
515
721
  claimed_intent_id: input.claimedIntentId,
516
722
  intent_anchor_token: input.intentAnchorToken,
517
723
  parent_action_id: input.parentActionId,
724
+ dry_run: mode === "evaluate",
518
725
  actor: input.actor
519
726
  ? {
520
727
  id: input.actor.id,
@@ -531,10 +738,128 @@ export class Auctra {
531
738
  }
532
739
  : undefined,
533
740
  },
534
- { ...options, idempotencyKey },
741
+ mode === "execute" ? { ...options, idempotencyKey } : options,
535
742
  );
536
743
  }
537
744
 
745
+ private async issueAuthorityRequest(
746
+ input: IssueAuthorityInput & { parentAuthorityId?: string },
747
+ ): Promise<{
748
+ authority: AuthoritySummary;
749
+ authority_id: string;
750
+ delegation: Delegation;
751
+ }> {
752
+ const response = await this.request<{
753
+ delegation: Delegation;
754
+ authority_id?: string;
755
+ authority?: AuthoritySummary;
756
+ }>("POST", "/v1/authorities", {
757
+ agent_id: input.subject,
758
+ action_types: input.capabilities,
759
+ valid_until: input.expiresAt,
760
+ max_amount: input.constraints?.maxAmount,
761
+ max_count: input.constraints?.maxCount,
762
+ environment: input.constraints?.environment,
763
+ currency: input.constraints?.currency,
764
+ delegator_user_id: input.delegatorUserId ?? input.issuer,
765
+ parent_authority_id: input.parentAuthorityId,
766
+ max_delegation_depth: input.delegation?.maxDepth,
767
+ max_actions_per_window: input.maxActionsPerWindow
768
+ ? {
769
+ count: input.maxActionsPerWindow.count,
770
+ window_seconds: input.maxActionsPerWindow.windowSeconds,
771
+ action_type: input.maxActionsPerWindow.actionType,
772
+ }
773
+ : undefined,
774
+ max_amount_per_window: input.maxAmountPerWindow
775
+ ? {
776
+ amount: input.maxAmountPerWindow.amount,
777
+ window_seconds: input.maxAmountPerWindow.windowSeconds,
778
+ }
779
+ : undefined,
780
+ });
781
+
782
+ const authorityId = response.authority_id ?? response.delegation.id;
783
+ const authority: AuthoritySummary = response.authority ?? {
784
+ id: authorityId,
785
+ protocol_version: "0.1",
786
+ status: response.delegation.status,
787
+ payload_hash: "",
788
+ signed: false,
789
+ parent_authority_id: input.parentAuthorityId ?? null,
790
+ capabilities: input.capabilities,
791
+ };
792
+
793
+ return {
794
+ authority,
795
+ authority_id: authorityId,
796
+ delegation: response.delegation,
797
+ };
798
+ }
799
+
800
+ /**
801
+ * Authority Protocol — issue, verify, delegate (subset), revoke.
802
+ * There is no legacy createDelegation() surface.
803
+ */
804
+ get authority() {
805
+ return {
806
+ issue: (input: IssueAuthorityInput) => this.issueAuthorityRequest(input),
807
+ verify: (
808
+ payload: Record<string, unknown>,
809
+ artifact: Record<string, unknown>,
810
+ ): Promise<{
811
+ valid: boolean;
812
+ hashValid: boolean;
813
+ signatureValid: boolean;
814
+ expired: boolean;
815
+ status: string;
816
+ issuer: string;
817
+ subject: string;
818
+ capabilities: string[];
819
+ constraints: Record<string, unknown>;
820
+ expiresAt: string;
821
+ protocolVersion: string;
822
+ }> => this.request("POST", "/v1/authorities/verify", { payload, artifact }),
823
+ delegate: (input: DelegateAuthorityInput) =>
824
+ this.issueAuthorityRequest({
825
+ ...input,
826
+ parentAuthorityId: input.parent,
827
+ }),
828
+ revoke: (authorityId: string): Promise<{ ok: true }> =>
829
+ this.request("POST", `/v1/authorities/${encodeURIComponent(authorityId)}/revoke`, {}),
830
+ };
831
+ }
832
+
833
+ /**
834
+ * Action Protocol — evaluate (dry-run) vs execute (enforce + evidence).
835
+ * There is no legacy evaluateAction() surface.
836
+ */
837
+ get action() {
838
+ return {
839
+ evaluate: (input: EvaluateActionInput, options: RequestOptions = {}) =>
840
+ this.executeOrEvaluateAction(input, options, "evaluate"),
841
+ execute: (input: EvaluateActionInput, options: RequestOptions = {}) =>
842
+ this.executeOrEvaluateAction(input, options, "execute"),
843
+ };
844
+ }
845
+
846
+ get evidence() {
847
+ return {
848
+ verify: (
849
+ payload: DecisionEvidencePayload,
850
+ evidence: DecisionEvidence,
851
+ ): Promise<ArtifactVerification> =>
852
+ this.request("POST", "/v1/evidence/verify", { payload, evidence }),
853
+ };
854
+ }
855
+
856
+ async verifyMandate(
857
+ payload: MandatePayload,
858
+ evidence: MandateEvidence,
859
+ ): Promise<ArtifactVerification> {
860
+ return this.request("POST", "/v1/mandates/verify", { payload, evidence });
861
+ }
862
+
538
863
  async listIntents(): Promise<{ intents: Intent[] }> {
539
864
  return this.request("GET", "/v1/intents");
540
865
  }
@@ -661,42 +986,12 @@ export class Auctra {
661
986
  return this.request("DELETE", `/v1/agents/${encodeURIComponent(agentId)}`);
662
987
  }
663
988
 
664
- async listDelegations(): Promise<{ delegations: Delegation[] }> {
665
- return this.request("GET", "/v1/delegations");
666
- }
667
-
668
- async getDelegation(delegationId: string): Promise<{ delegation: Delegation }> {
669
- return this.request("GET", `/v1/delegations/${encodeURIComponent(delegationId)}`);
670
- }
671
-
672
- async createDelegation(input: CreateDelegationInput): Promise<{ delegation: Delegation }> {
673
- return this.request("POST", "/v1/delegations", {
674
- agent_id: input.agentId,
675
- action_types: input.actionTypes,
676
- valid_until: input.validUntil,
677
- max_amount: input.maxAmount,
678
- max_count: input.maxCount,
679
- environment: input.environment,
680
- currency: input.currency,
681
- delegator_user_id: input.delegatorUserId,
682
- max_actions_per_window: input.maxActionsPerWindow
683
- ? {
684
- count: input.maxActionsPerWindow.count,
685
- window_seconds: input.maxActionsPerWindow.windowSeconds,
686
- action_type: input.maxActionsPerWindow.actionType,
687
- }
688
- : undefined,
689
- max_amount_per_window: input.maxAmountPerWindow
690
- ? {
691
- amount: input.maxAmountPerWindow.amount,
692
- window_seconds: input.maxAmountPerWindow.windowSeconds,
693
- }
694
- : undefined,
695
- });
989
+ async listAuthorities(): Promise<{ delegations: Delegation[]; authorities?: AuthoritySummary[] }> {
990
+ return this.request("GET", "/v1/authorities");
696
991
  }
697
992
 
698
- async revokeDelegation(delegationId: string): Promise<{ ok: true }> {
699
- return this.request("POST", `/v1/delegations/${encodeURIComponent(delegationId)}/revoke`, {});
993
+ async getAuthority(authorityId: string): Promise<{ delegation: Delegation }> {
994
+ return this.request("GET", `/v1/authorities/${encodeURIComponent(authorityId)}`);
700
995
  }
701
996
 
702
997
  async listActionRequests(): Promise<{ action_requests: ActionRequest[] }> {
@@ -816,6 +1111,14 @@ export class Auctra {
816
1111
  return this.request("GET", "/v1/audit-events");
817
1112
  }
818
1113
 
1114
+ async getAuditEvent(auditEventId: string): Promise<{ audit_event: AuditEvent }> {
1115
+ return this.request("GET", `/v1/audit-events/${encodeURIComponent(auditEventId)}`);
1116
+ }
1117
+
1118
+ async verifyAuditChain(): Promise<AuditChainVerification> {
1119
+ return this.request("GET", "/v1/audit-events/verify");
1120
+ }
1121
+
819
1122
  async listApiKeys(): Promise<{ api_keys: ApiKeySummary[] }> {
820
1123
  return this.request("GET", "/v1/api-keys");
821
1124
  }