@umpledger/sdk 2.0.0-alpha.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.
@@ -0,0 +1,140 @@
1
+ /**
2
+ * UMP v2.0 — Multi-Agent Marketplace Example
3
+ *
4
+ * Demonstrates the AI Agent API Marketplace use case from the spec:
5
+ * A coding agent discovers a security-review agent, negotiates pricing,
6
+ * submits work, verifies outcomes, and settles payment — all autonomously.
7
+ *
8
+ * Run: npx tsx examples/multi-agent-marketplace.ts
9
+ */
10
+ import { UMP, PricingTemplates } from '../src';
11
+
12
+ async function main() {
13
+ const ump = new UMP({
14
+ apiKey: 'ump_sk_marketplace_demo',
15
+ onAudit: (r) => console.log(` [AUDIT] ${r.what.operation}: $${r.what.amount ?? 0}`),
16
+ });
17
+
18
+ console.log('═══ Multi-Agent Marketplace Demo ═══\n');
19
+
20
+ // ── 1. Set up the enterprise org ──
21
+ const acmeOrg = ump.registerAgent({
22
+ name: 'Acme Corp',
23
+ type: 'ORGANIZATION',
24
+ authority: { maxPerTransaction: '$500', maxPerDay: '$5000', maxPerMonth: '$50000' },
25
+ });
26
+ acmeOrg.wallet.fund({ amount: '$10000' });
27
+ console.log(`✓ Org registered: ${acmeOrg.id} (balance: $${acmeOrg.wallet.balance()})`);
28
+
29
+ // ── 2. Org creates an AI coding agent ──
30
+ const codingAgent = ump.registerAgent({
31
+ name: 'acme-coding-agent',
32
+ type: 'AI_AGENT',
33
+ capabilities: ['code_generation', 'refactoring'],
34
+ authority: {
35
+ maxPerTransaction: '$100',
36
+ maxPerDay: '$1000',
37
+ },
38
+ });
39
+ codingAgent.wallet.fund({ amount: '$500' });
40
+
41
+ // ── 3. Security review service registers ──
42
+ const securityAgent = ump.registerAgent({
43
+ name: 'security-review-service',
44
+ type: 'SERVICE',
45
+ capabilities: ['security_review', 'vulnerability_scan'],
46
+ authority: {
47
+ maxPerTransaction: '$200',
48
+ maxPerDay: '$10000',
49
+ },
50
+ });
51
+ console.log(`✓ Security service: ${securityAgent.id}`);
52
+
53
+ // ── 4. Dynamic contract negotiation ──
54
+ console.log('\n── Contract Negotiation ──');
55
+
56
+ // Coding agent proposes
57
+ const proposal = ump.contracts.propose(codingAgent.id, {
58
+ targetAgentId: securityAgent.id,
59
+ pricingRules: [{
60
+ name: 'Per-file static analysis',
61
+ primitive: 'UNIT_RATE',
62
+ rate: 0.05,
63
+ unit: 'FILE',
64
+ } as any],
65
+ });
66
+ console.log(` Proposal: $0.05/file (status: ${proposal.status})`);
67
+
68
+ // Security agent counters with tiered pricing
69
+ const counter = ump.contracts.counter(proposal.contractId, securityAgent.id, [{
70
+ name: 'Deep review tiered',
71
+ primitive: 'TIERED',
72
+ mode: 'GRADUATED',
73
+ tiers: [
74
+ { from: 0, to: 50, rate: 0.50 },
75
+ { from: 50, to: 200, rate: 0.35 },
76
+ { from: 200, to: null, rate: 0.20 },
77
+ ],
78
+ } as any]);
79
+ console.log(` Counter: $0.50/file (first 50), $0.35 (50-200), $0.20 (200+) (status: ${counter.status})`);
80
+
81
+ // Coding agent accepts
82
+ const accepted = ump.contracts.accept(counter.contractId);
83
+ console.log(` ✓ Contract accepted: ${accepted.contractId}\n`);
84
+
85
+ // ── 5. Create escrow for 94 files ──
86
+ console.log('── Escrow & Execution ──');
87
+ const fileCount = 94;
88
+ const estimatedCost = 50 * 0.50 + 44 * 0.35; // $25 + $15.40 = $40.40
89
+ console.log(` Estimated cost for ${fileCount} files: $${estimatedCost.toFixed(2)}`);
90
+
91
+ const escrowId = ump.settlement.createEscrow(
92
+ codingAgent.id,
93
+ securityAgent.id,
94
+ estimatedCost,
95
+ 'txn_security_review_1',
96
+ );
97
+ console.log(` ✓ Escrow created: ${escrowId}`);
98
+ console.log(` Buyer balance: $${codingAgent.wallet.balance()} (${estimatedCost} reserved)`);
99
+
100
+ // ── 6. Simulate execution — meter per-file events ──
101
+ for (let i = 0; i < fileCount; i++) {
102
+ ump.metering.record({
103
+ sourceAgentId: codingAgent.id,
104
+ targetAgentId: securityAgent.id,
105
+ contractId: accepted.contractId,
106
+ serviceId: 'deep_security_review',
107
+ quantity: 1,
108
+ unit: 'FILE',
109
+ dimensions: { filename: `src/file_${i}.ts`, severity_findings: Math.floor(Math.random() * 3) },
110
+ });
111
+ }
112
+ console.log(` ✓ Metered ${fileCount} file review events`);
113
+
114
+ // ── 7. Release escrow upon verified outcome ──
115
+ const outcome = ump.metering.attestOutcome({
116
+ outcomeType: 'TASK_COMPLETION',
117
+ claimedBy: securityAgent.id,
118
+ evidence: [
119
+ { type: 'LOG', uri: 'ump://evidence/scan_report_001', hash: 'sha256:abc123', description: '94 files reviewed' },
120
+ { type: 'METRIC', uri: 'ump://evidence/findings_summary', hash: 'sha256:def456', description: '12 critical, 23 warnings' },
121
+ ],
122
+ verificationMethod: 'BILATERAL_AGREEMENT',
123
+ confidenceScore: 0.95,
124
+ });
125
+ console.log(` ✓ Outcome attested: ${outcome.outcomeId} (confidence: ${outcome.confidenceScore})`);
126
+
127
+ const { settlement } = ump.settlement.releaseEscrow(escrowId, estimatedCost);
128
+ console.log(` ✓ Settlement complete: $${settlement.totalAmount.toFixed(2)} released to security agent`);
129
+
130
+ // ── 8. Final state ──
131
+ console.log('\n── Final State ──');
132
+ console.log(` Coding agent balance: $${codingAgent.wallet.balance().toFixed(2)}`);
133
+ console.log(` Security agent balance: $${securityAgent.wallet.balance().toFixed(2)}`);
134
+ console.log(` Audit records: ${ump.audit.count()}`);
135
+ console.log(` Usage events: ${ump.metering.getByAgent(codingAgent.id).length}`);
136
+
137
+ console.log('\n✓ Multi-agent marketplace demo complete!');
138
+ }
139
+
140
+ main().catch(console.error);
@@ -0,0 +1,107 @@
1
+ /**
2
+ * UMP v2.0 — Quick Start Example
3
+ *
4
+ * This example demonstrates the core flow:
5
+ * Register agents → Fund wallets → Create contracts → Transact
6
+ *
7
+ * Run: npx tsx examples/quickstart.ts
8
+ */
9
+ import { UMP, PricingTemplates } from '../src';
10
+
11
+ async function main() {
12
+ // ── 1. Initialize UMP ──
13
+ const ump = new UMP({
14
+ apiKey: 'ump_sk_demo_123',
15
+ onAudit: (record) => {
16
+ console.log(`[AUDIT] ${record.what.operation}: $${record.what.amount ?? 0}`);
17
+ },
18
+ });
19
+
20
+ // ── 2. Register your AI agent with spending limits ──
21
+ const codingAgent = ump.registerAgent({
22
+ name: 'my-coding-agent',
23
+ type: 'AI_AGENT',
24
+ capabilities: ['code_review', 'refactoring', 'testing'],
25
+ authority: {
26
+ maxPerTransaction: '$50',
27
+ maxPerDay: '$500',
28
+ maxPerMonth: '$5000',
29
+ },
30
+ });
31
+
32
+ console.log(`✓ Registered agent: ${codingAgent.id}`);
33
+
34
+ // ── 3. Register the service agent ──
35
+ const reviewService = ump.registerAgent({
36
+ name: 'code-review-service',
37
+ type: 'SERVICE',
38
+ capabilities: ['security_review', 'performance_review'],
39
+ authority: {
40
+ maxPerTransaction: '$100',
41
+ maxPerDay: '$10000',
42
+ },
43
+ });
44
+
45
+ console.log(`✓ Registered service: ${reviewService.id}`);
46
+
47
+ // ── 4. Fund the agent's wallet ──
48
+ codingAgent.wallet.fund({ amount: '$100' });
49
+ console.log(`✓ Funded wallet: $${codingAgent.wallet.balance()}`);
50
+
51
+ // ── 5. Create a contract with pricing rules ──
52
+ const contract = ump.contracts.create(codingAgent.id, {
53
+ targetAgentId: reviewService.id,
54
+ pricingRules: [
55
+ PricingTemplates.agentTask(0.50, 1.00), // $0.50/task + $1.00 bonus on success
56
+ ],
57
+ });
58
+
59
+ console.log(`✓ Contract created: ${contract.contractId}`);
60
+
61
+ // ── 6. Execute a transaction ──
62
+ const result = await ump.transact({
63
+ from: codingAgent.id,
64
+ to: reviewService.id,
65
+ service: 'code_review',
66
+ payload: {
67
+ repo: 'github.com/acme/app',
68
+ pr: 42,
69
+ files: ['src/auth.ts', 'src/payments.ts'],
70
+ },
71
+ });
72
+
73
+ console.log(`\n═══ Transaction Result ═══`);
74
+ console.log(` Cost: $${result.cost}`);
75
+ console.log(` Audit: ${result.auditId}`);
76
+ console.log(` Speed: ${result.duration}ms`);
77
+ console.log(` Balance: $${codingAgent.wallet.balance()}`);
78
+
79
+ // ── 7. Check the ledger ──
80
+ const wallet = ump.wallets.getByAgent(codingAgent.id);
81
+ const ledger = ump.wallets.getLedger(wallet.walletId);
82
+ console.log(`\n═══ Spending Ledger (${ledger.length} entries) ═══`);
83
+ for (const entry of ledger) {
84
+ console.log(` ${entry.type.padEnd(8)} $${entry.amount.toFixed(2).padStart(8)} ${entry.description}`);
85
+ }
86
+
87
+ // ── 8. Simulate pricing scenarios ──
88
+ const perTokenRule = PricingTemplates.perToken(30, 60);
89
+ console.log(`\n═══ Pricing Simulation ═══`);
90
+ console.log(` 1M input tokens: $${ump.pricing.simulate(perTokenRule, 1_000_000, { direction: 'input' })}`);
91
+ console.log(` 1M output tokens: $${ump.pricing.simulate(perTokenRule, 1_000_000, { direction: 'output' })}`);
92
+
93
+ const hybridRule = PricingTemplates.subscriptionPlusUsage(99, 1000, 0.05);
94
+ console.log(` 500 calls (sub): $${ump.pricing.simulate(hybridRule, 500)}`);
95
+ console.log(` 2000 calls (sub): $${ump.pricing.simulate(hybridRule, 2000)}`);
96
+
97
+ // ── 9. Query audit trail ──
98
+ const audits = ump.audit.query({ agentId: codingAgent.id });
99
+ console.log(`\n═══ Audit Trail (${audits.length} records) ═══`);
100
+ for (const a of audits) {
101
+ console.log(` [${a.when.toISOString()}] ${a.what.operation} - ${a.result.status}`);
102
+ }
103
+
104
+ console.log(`\n✓ Done! UMP v2.0 Quick Start complete.`);
105
+ }
106
+
107
+ main().catch(console.error);
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "@umpledger/sdk",
3
+ "version": "2.0.0-alpha.1",
4
+ "description": "Universal Monetization Protocol SDK — The payment rail for the autonomous economy",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "module": "dist/index.mjs",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./pricing": {
15
+ "import": "./dist/pricing/index.mjs",
16
+ "require": "./dist/pricing/index.js",
17
+ "types": "./dist/pricing/index.d.ts"
18
+ }
19
+ },
20
+ "scripts": {
21
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
22
+ "test": "vitest run",
23
+ "test:watch": "vitest",
24
+ "lint": "eslint src/ --ext .ts",
25
+ "typecheck": "tsc --noEmit",
26
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
27
+ },
28
+ "keywords": [
29
+ "monetization",
30
+ "ai-agents",
31
+ "billing",
32
+ "pricing",
33
+ "settlement",
34
+ "agent-commerce",
35
+ "protocol"
36
+ ],
37
+ "author": "UMPLedger",
38
+ "license": "Apache-2.0",
39
+ "homepage": "https://umpledger.com",
40
+ "repository": {
41
+ "type": "git",
42
+ "url": "https://github.com/umpledger/ump-protocol"
43
+ },
44
+ "engines": {
45
+ "node": ">=18.0.0"
46
+ },
47
+ "dependencies": {
48
+ "uuid": "^9.0.1"
49
+ },
50
+ "devDependencies": {
51
+ "@types/node": "^20.19.37",
52
+ "@types/uuid": "^9.0.8",
53
+ "eslint": "^8.50.0",
54
+ "tsup": "^8.5.1",
55
+ "typescript": "^5.9.3",
56
+ "vitest": "^1.0.0"
57
+ }
58
+ }
@@ -0,0 +1,200 @@
1
+ import type {
2
+ AgentIdentity, AgentStatus, AgentType, AuthorityScope,
3
+ CreateAgentOptions, VerificationProof,
4
+ } from '../types';
5
+ import { generateId, parseMoney, hrTimestamp } from '../utils/id';
6
+ import { AgentNotFoundError, AgentRevokedError } from '../utils/errors';
7
+ import crypto from 'crypto';
8
+
9
+ /**
10
+ * AgentManager — Layer 1 primitive
11
+ *
12
+ * Manages Agent Identity lifecycle: creation, verification,
13
+ * authority scope enforcement, hierarchical revocation.
14
+ */
15
+ export class AgentManager {
16
+ private agents: Map<string, AgentIdentity> = new Map();
17
+
18
+ /**
19
+ * Register a new Agent Identity with authority scope.
20
+ */
21
+ create(options: CreateAgentOptions): AgentIdentity {
22
+ const agentId = generateId('agt');
23
+ const now = hrTimestamp();
24
+
25
+ // Generate ephemeral keypair for this agent
26
+ const { publicKey, privateKey } = crypto.generateKeyPairSync('ed25519');
27
+ const pubKeyHex = publicKey.export({ type: 'spki', format: 'der' }).toString('hex');
28
+
29
+ // Normalize authority scope — parse "$50" strings into numbers
30
+ const authority: AuthorityScope = {
31
+ maxPerTransaction: parseMoney(options.authority.maxPerTransaction),
32
+ maxPerDay: parseMoney(options.authority.maxPerDay),
33
+ maxPerMonth: options.authority.maxPerMonth
34
+ ? parseMoney(options.authority.maxPerMonth)
35
+ : parseMoney(options.authority.maxPerDay) * 30,
36
+ allowedServices: options.authority.allowedServices,
37
+ allowedCounterparties: options.authority.allowedCounterparties,
38
+ requiresApprovalAbove: options.authority.requiresApprovalAbove,
39
+ autoRevokeAfter: options.authority.autoRevokeAfter,
40
+ };
41
+
42
+ // If parent exists, child authority cannot exceed parent's
43
+ if (options.parentId) {
44
+ const parent = this.get(options.parentId);
45
+ authority.maxPerTransaction = Math.min(authority.maxPerTransaction, parent.authorityScope.maxPerTransaction);
46
+ authority.maxPerDay = Math.min(authority.maxPerDay, parent.authorityScope.maxPerDay);
47
+ authority.maxPerMonth = Math.min(authority.maxPerMonth, parent.authorityScope.maxPerMonth);
48
+ }
49
+
50
+ const verification: VerificationProof = {
51
+ publicKey: pubKeyHex,
52
+ issuingAuthority: 'ump-sdk-local',
53
+ expiresAt: new Date(now.getTime() + (options.authority.autoRevokeAfter || 365 * 24 * 60 * 60 * 1000)),
54
+ };
55
+
56
+ const agent: AgentIdentity = {
57
+ agentId,
58
+ agentType: options.type,
59
+ parentId: options.parentId || null,
60
+ displayName: options.name,
61
+ capabilities: options.capabilities || [],
62
+ authorityScope: authority,
63
+ verification,
64
+ metadata: {
65
+ ...options.metadata,
66
+ _privateKey: privateKey.export({ type: 'pkcs8', format: 'der' }).toString('hex'),
67
+ },
68
+ status: 'ACTIVE',
69
+ createdAt: now,
70
+ updatedAt: now,
71
+ };
72
+
73
+ this.agents.set(agentId, agent);
74
+
75
+ // Schedule auto-revoke if set
76
+ if (options.authority.autoRevokeAfter) {
77
+ setTimeout(() => this.revoke(agentId), options.authority.autoRevokeAfter);
78
+ }
79
+
80
+ return agent;
81
+ }
82
+
83
+ /**
84
+ * Retrieve an agent by ID.
85
+ */
86
+ get(agentId: string): AgentIdentity {
87
+ const agent = this.agents.get(agentId);
88
+ if (!agent) throw new AgentNotFoundError(agentId);
89
+ return agent;
90
+ }
91
+
92
+ /**
93
+ * Update authority scope (tightening is always allowed; loosening requires parent).
94
+ */
95
+ updateAuthority(agentId: string, newScope: Partial<AuthorityScope>): AgentIdentity {
96
+ const agent = this.get(agentId);
97
+ if (agent.status !== 'ACTIVE') throw new AgentRevokedError(agentId);
98
+
99
+ const updated: AgentIdentity = {
100
+ ...agent,
101
+ authorityScope: { ...agent.authorityScope, ...newScope },
102
+ updatedAt: hrTimestamp(),
103
+ };
104
+
105
+ this.agents.set(agentId, updated);
106
+ return updated;
107
+ }
108
+
109
+ /**
110
+ * Revoke an agent and cascade to all children.
111
+ */
112
+ revoke(agentId: string): string[] {
113
+ const revoked: string[] = [];
114
+ const agent = this.agents.get(agentId);
115
+ if (!agent) return revoked;
116
+
117
+ agent.status = 'REVOKED';
118
+ agent.updatedAt = hrTimestamp();
119
+ revoked.push(agentId);
120
+
121
+ // Cascade: revoke all children
122
+ for (const [id, a] of this.agents) {
123
+ if (a.parentId === agentId && a.status === 'ACTIVE') {
124
+ revoked.push(...this.revoke(id));
125
+ }
126
+ }
127
+
128
+ return revoked;
129
+ }
130
+
131
+ /**
132
+ * Verify that an agent's identity is valid and active.
133
+ */
134
+ verify(agentId: string): { valid: boolean; reason?: string } {
135
+ const agent = this.agents.get(agentId);
136
+ if (!agent) return { valid: false, reason: 'Agent not found' };
137
+ if (agent.status !== 'ACTIVE') return { valid: false, reason: `Agent status: ${agent.status}` };
138
+ if (agent.verification.expiresAt < new Date()) {
139
+ agent.status = 'EXPIRED';
140
+ return { valid: false, reason: 'Verification expired' };
141
+ }
142
+ return { valid: true };
143
+ }
144
+
145
+ /**
146
+ * Check if a transaction amount is within the agent's authority scope.
147
+ */
148
+ checkAuthority(
149
+ agentId: string,
150
+ amount: number,
151
+ counterpartyId?: string,
152
+ serviceId?: string
153
+ ): { allowed: boolean; reason?: string; requiresApproval?: boolean } {
154
+ const agent = this.get(agentId);
155
+ const scope = agent.authorityScope;
156
+
157
+ if (agent.status !== 'ACTIVE') {
158
+ return { allowed: false, reason: `Agent status: ${agent.status}` };
159
+ }
160
+
161
+ if (amount > scope.maxPerTransaction) {
162
+ return { allowed: false, reason: `Exceeds per-transaction limit of ${scope.maxPerTransaction}` };
163
+ }
164
+
165
+ if (scope.allowedCounterparties && counterpartyId) {
166
+ const allowed = scope.allowedCounterparties.some(pattern => {
167
+ if (pattern.endsWith('*')) {
168
+ return counterpartyId.startsWith(pattern.slice(0, -1));
169
+ }
170
+ return counterpartyId === pattern;
171
+ });
172
+ if (!allowed) {
173
+ return { allowed: false, reason: `Counterparty ${counterpartyId} not in allowlist` };
174
+ }
175
+ }
176
+
177
+ if (scope.allowedServices && serviceId) {
178
+ if (!scope.allowedServices.includes(serviceId)) {
179
+ return { allowed: false, reason: `Service ${serviceId} not in allowlist` };
180
+ }
181
+ }
182
+
183
+ if (scope.requiresApprovalAbove && amount > scope.requiresApprovalAbove) {
184
+ return { allowed: true, requiresApproval: true };
185
+ }
186
+
187
+ return { allowed: true };
188
+ }
189
+
190
+ /**
191
+ * List all agents, optionally filtered.
192
+ */
193
+ list(filter?: { parentId?: string; type?: AgentType; status?: AgentStatus }): AgentIdentity[] {
194
+ let results = Array.from(this.agents.values());
195
+ if (filter?.parentId) results = results.filter(a => a.parentId === filter.parentId);
196
+ if (filter?.type) results = results.filter(a => a.agentType === filter.type);
197
+ if (filter?.status) results = results.filter(a => a.status === filter.status);
198
+ return results;
199
+ }
200
+ }
@@ -0,0 +1,91 @@
1
+ import type { AuditRecord } from '../types';
2
+ import { generateId, hrTimestamp } from '../utils/id';
3
+
4
+ /**
5
+ * AuditTrail — Layer 3 primitive
6
+ *
7
+ * Immutable append-only log of every UMP operation.
8
+ * Captures 6 dimensions: WHAT, WHO, WHEN, WHY, HOW, RESULT.
9
+ */
10
+ export class AuditTrail {
11
+ private records: AuditRecord[] = [];
12
+ private onAudit?: (record: AuditRecord) => void;
13
+
14
+ constructor(onAudit?: (record: AuditRecord) => void) {
15
+ this.onAudit = onAudit;
16
+ }
17
+
18
+ /**
19
+ * Record an audit entry. Returns the audit ID.
20
+ */
21
+ record(data: Omit<AuditRecord, 'auditId' | 'when'>): string {
22
+ const auditId = generateId('aud');
23
+ const record: AuditRecord = {
24
+ auditId,
25
+ when: hrTimestamp(),
26
+ ...data,
27
+ };
28
+ this.records.push(record);
29
+
30
+ // Fire callback if registered (for real-time dashboards, etc.)
31
+ if (this.onAudit) {
32
+ this.onAudit(record);
33
+ }
34
+
35
+ return auditId;
36
+ }
37
+
38
+ /**
39
+ * Query audit records with filters.
40
+ */
41
+ query(filters?: {
42
+ agentId?: string;
43
+ operation?: string;
44
+ fromDate?: Date;
45
+ toDate?: Date;
46
+ minAmount?: number;
47
+ contractId?: string;
48
+ }, limit = 100, offset = 0): AuditRecord[] {
49
+ let results = this.records;
50
+
51
+ if (filters) {
52
+ if (filters.agentId) {
53
+ results = results.filter(r =>
54
+ r.who.sourceAgentId === filters.agentId ||
55
+ r.who.targetAgentId === filters.agentId
56
+ );
57
+ }
58
+ if (filters.operation) {
59
+ results = results.filter(r => r.what.operation === filters.operation);
60
+ }
61
+ if (filters.fromDate) {
62
+ results = results.filter(r => r.when >= filters.fromDate!);
63
+ }
64
+ if (filters.toDate) {
65
+ results = results.filter(r => r.when <= filters.toDate!);
66
+ }
67
+ if (filters.minAmount !== undefined) {
68
+ results = results.filter(r => (r.what.amount || 0) >= filters.minAmount!);
69
+ }
70
+ if (filters.contractId) {
71
+ results = results.filter(r => r.why.contractId === filters.contractId);
72
+ }
73
+ }
74
+
75
+ return results.slice(offset, offset + limit);
76
+ }
77
+
78
+ /**
79
+ * Get a specific audit record by ID.
80
+ */
81
+ get(auditId: string): AuditRecord | undefined {
82
+ return this.records.find(r => r.auditId === auditId);
83
+ }
84
+
85
+ /**
86
+ * Get total count of records.
87
+ */
88
+ count(): number {
89
+ return this.records.length;
90
+ }
91
+ }
@@ -0,0 +1,3 @@
1
+ export { AgentManager } from './agent-manager';
2
+ export { WalletManager } from './wallet-manager';
3
+ export { AuditTrail } from './audit-trail';