@emilia-protocol/sdk 0.1.0 → 0.9.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/README.md ADDED
@@ -0,0 +1,810 @@
1
+ # @emilia-protocol/sdk
2
+
3
+ **Trust before high-risk action.**
4
+
5
+ The official TypeScript SDK for the [EMILIA Protocol](https://emiliaprotocol.ai) — the protocol-grade trust substrate for high-risk action enforcement across AI agents, enterprise systems, government workflows, and financial operations.
6
+
7
+ EMILIA maps to six design pillars: **E**vidence, **M**ediation, **I**dentity, **L**ineage, **I**nvocation, **A**ppeals.
8
+
9
+ > Constitutional principle: **trust must never be more powerful than appeal.**
10
+
11
+ ---
12
+
13
+ ## Table of Contents
14
+
15
+ - [Installation](#installation)
16
+ - [Quick Start](#quick-start)
17
+ - [Environment Variables](#environment-variables)
18
+ - [Core Concepts](#core-concepts)
19
+ - [API Reference](#api-reference)
20
+ - [Trust Profile](#trust-profile)
21
+ - [Trust Evaluation](#trust-evaluation)
22
+ - [Trust Gate](#trust-gate)
23
+ - [Domain Scores](#domain-scores)
24
+ - [Pre-Action Enforcement (experimental)](#install-preflight)
25
+ - [Entities](#entities)
26
+ - [Receipts](#receipts)
27
+ - [Disputes & Due Process](#disputes--due-process)
28
+ - [Delegation](#delegation)
29
+ - [Identity Continuity](#identity-continuity)
30
+ - [Policies](#policies)
31
+ - [System](#system)
32
+ - [Error Handling](#error-handling)
33
+ - [TypeScript Usage](#typescript-usage)
34
+ - [Links](#links)
35
+ - [License](#license)
36
+
37
+ ---
38
+
39
+ ## Installation
40
+
41
+ ```bash
42
+ npm install @emilia-protocol/sdk
43
+ ```
44
+
45
+ Requires Node.js 18 or later (native `fetch` is used).
46
+
47
+ ---
48
+
49
+ ## Quick Start
50
+
51
+ ```typescript
52
+ import { EPClient } from '@emilia-protocol/sdk';
53
+
54
+ const ep = new EPClient({ apiKey: process.env.EP_API_KEY });
55
+
56
+ const profile = await ep.trustProfile('merchant-xyz');
57
+ console.log(profile.current_confidence); // "confident"
58
+ console.log(profile.trust_profile?.behavioral?.completion_rate); // 97.2
59
+
60
+ const evaluation = await ep.trustEvaluate('merchant-xyz', 'strict');
61
+ if (evaluation.decision !== 'allow') throw new Error(`Trust check failed: ${evaluation.reasons?.join(', ')}`);
62
+ ```
63
+
64
+ ---
65
+
66
+ ## Environment Variables
67
+
68
+ | Variable | Description | Default |
69
+ |---|---|---|
70
+ | `EP_API_KEY` | Your EP API key (`ep_live_...`). Required for write operations. | — |
71
+ | `EP_BASE_URL` | Override the API base URL (useful for local dev). | `https://emiliaprotocol.ai` |
72
+
73
+ You can also pass these directly to the constructor:
74
+
75
+ ```typescript
76
+ const ep = new EPClient({
77
+ apiKey: 'ep_live_...',
78
+ baseUrl: 'http://localhost:3000', // local dev
79
+ timeout: 10_000, // 10 seconds (default: 30s)
80
+ });
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Core Concepts
86
+
87
+ ### Trust Profile
88
+
89
+ The trust profile is the canonical EP read surface. It aggregates behavioral rates, signal scores, provenance breakdown, consistency, anomaly detection, and dispute history into a single structured object. Always start here.
90
+
91
+ ```
92
+ profile.current_confidence → "pending" | "insufficient" | "provisional" | "emerging" | "confident"
93
+ profile.trust_profile.behavioral.completion_rate → float (0-100)
94
+ profile.trust_profile.signals.delivery_accuracy → float (0-100)
95
+ profile.trust_profile.provenance.bilateral_rate → float (0-100)
96
+ profile.anomaly → present only when anomaly detected
97
+ ```
98
+
99
+ ### Receipts
100
+
101
+ Receipts are the atomic unit of evidence in EP. Every interaction between principals generates a receipt. Receipts are:
102
+
103
+ - **Append-only** — cannot be edited or deleted
104
+ - **Cryptographically hashed** — SHA-256 of the canonical payload
105
+ - **Chain-linked** — each receipt references the previous hash for the entity
106
+ - **Anchored** — periodically committed to a Merkle root for external verification
107
+
108
+ The `agent_behavior` field is the strongest Phase 1 signal. Always set it.
109
+
110
+ ### Policy Evaluation
111
+
112
+ Policies define trust thresholds. EP ships 8 named policies:
113
+
114
+ | Policy | Family | Use case |
115
+ |---|---|---|
116
+ | `strict` | core | High-value transactions, sensitive data |
117
+ | `standard` | core | Normal commerce, default |
118
+ | `permissive` | core | Low-risk interactions |
119
+ | `discovery` | core | Allow unevaluated entities to participate |
120
+ | `mcp_server_safe_v1` | software | MCP server installation |
121
+ | `npm_buildtime_safe_v1` | software | npm package installation in CI |
122
+ | `browser_extension_safe_v1` | software | Browser extension installation |
123
+ | `github_private_repo_safe_v1` | software | GitHub App with private repo access |
124
+
125
+ ### Trust Gate
126
+
127
+ The trust gate is a pre-action decision surface that combines trust evaluation with delegation verification. Call it before any high-stakes autonomous action. It returns `allow | review | deny` with appeal paths for non-allow decisions.
128
+
129
+ ### Due Process
130
+
131
+ EP enforces a mandatory due process pipeline for every negative trust event:
132
+
133
+ 1. **Dispute** — any affected party can challenge a receipt
134
+ 2. **Response** — the receipt submitter has 7 days to respond
135
+ 3. **Resolution** — EP resolves with rationale (`upheld | reversed | dismissed`)
136
+ 4. **Appeal** — participants can appeal the resolution
137
+ 5. **Human Report** — no auth required; any human can report trust issues
138
+
139
+ ---
140
+
141
+ ## API Reference
142
+
143
+ ### Trust Profile
144
+
145
+ #### `ep.trustProfile(entityId)`
146
+
147
+ Get an entity's full trust profile. This is the canonical EP read surface.
148
+
149
+ ```typescript
150
+ const profile = await ep.trustProfile('merchant-xyz');
151
+
152
+ console.log(profile.entity_id); // "merchant-xyz"
153
+ console.log(profile.display_name); // "Merchant XYZ"
154
+ console.log(profile.current_confidence); // "confident"
155
+ console.log(profile.historical_establishment); // true
156
+ console.log(profile.effective_evidence_current); // 42
157
+ console.log(profile.receipt_count); // 57
158
+ console.log(profile.unique_submitters); // 12
159
+
160
+ // Behavioral rates
161
+ const b = profile.trust_profile?.behavioral;
162
+ console.log(b?.completion_rate); // 97.2
163
+ console.log(b?.retry_rate); // 1.8
164
+ console.log(b?.abandon_rate); // 0.5
165
+ console.log(b?.dispute_rate); // 0.5
166
+
167
+ // Signal scores
168
+ const s = profile.trust_profile?.signals;
169
+ console.log(s?.delivery_accuracy); // 96.1
170
+ console.log(s?.product_accuracy); // 94.8
171
+ console.log(s?.price_integrity); // 99.2
172
+ console.log(s?.return_processing); // 88.0
173
+
174
+ // Provenance
175
+ const prov = profile.trust_profile?.provenance;
176
+ console.log(prov?.breakdown); // { bilateral: 0.6, self_attested: 0.4 }
177
+ console.log(prov?.bilateral_rate); // 60
178
+
179
+ // Disputes
180
+ console.log(profile.disputes?.total); // 2
181
+ console.log(profile.disputes?.active); // 0
182
+ console.log(profile.disputes?.reversed); // 1
183
+
184
+ // Anomaly detection (only present when triggered)
185
+ if (profile.anomaly) {
186
+ console.warn(profile.anomaly.alert); // "Sudden drop: 23 points in 7 days"
187
+ }
188
+
189
+ // Legacy score (fallback only — prefer trust_profile for decisions)
190
+ console.log(profile.compat_score); // 91
191
+ ```
192
+
193
+ ---
194
+
195
+ ### Trust Evaluation
196
+
197
+ #### `ep.trustEvaluate(entityId, policy?, context?)`
198
+
199
+ Evaluate an entity against a named trust policy.
200
+
201
+ ```typescript
202
+ // Basic evaluation — returns a canonical TrustDecision
203
+ const result = await ep.trustEvaluate('merchant-xyz', 'standard');
204
+ console.log(result.decision); // "allow"
205
+ console.log(result.confidence); // "confident"
206
+
207
+ // With context for context-aware evaluation
208
+ const strict = await ep.trustEvaluate('merchant-xyz', 'strict', {
209
+ category: 'furniture',
210
+ geo: 'US-CA',
211
+ value_band: 'high',
212
+ });
213
+
214
+ if (strict.decision !== 'allow') {
215
+ console.error('Reasons:', strict.reasons);
216
+ // e.g. ["insufficient_evidence_current", "dispute_rate_too_high"]
217
+ console.warn('Warnings:', strict.warnings);
218
+ }
219
+
220
+ // Check which policy was applied (useful when policies cascade)
221
+ console.log(strict.policy_used); // "strict"
222
+ ```
223
+
224
+ ---
225
+
226
+ ### Trust Gate
227
+
228
+ #### `ep.trustGate(options)`
229
+
230
+ Pre-action trust check. Combines trust evaluation with delegation verification.
231
+
232
+ ```typescript
233
+ const gate = await ep.trustGate({
234
+ entityId: 'payment-agent-v2',
235
+ action: 'execute_payment',
236
+ policy: 'strict',
237
+ valueUsd: 750,
238
+ });
239
+
240
+ // gate.decision: "allow" | "review" | "deny"
241
+ if (gate.decision === 'allow') {
242
+ // Proceed with action
243
+ } else {
244
+ console.error('Gate denied:', gate.reasons);
245
+ console.log('Appeal path:', gate.appeal_path);
246
+ }
247
+
248
+ // With delegation verification
249
+ const gateWithDelegation = await ep.trustGate({
250
+ entityId: 'acme-payment-agent',
251
+ action: 'purchase',
252
+ policy: 'standard',
253
+ valueUsd: 200,
254
+ delegationId: 'ep_del_abc123',
255
+ });
256
+ console.log(gateWithDelegation.delegation_verified); // true
257
+ ```
258
+
259
+ ---
260
+
261
+ ### Domain Scores
262
+
263
+ #### `ep.domainScore(entityId, domains?)`
264
+
265
+ Get trust scores broken down by domain. Useful when you need trust context scoped to a specific action category.
266
+
267
+ ```typescript
268
+ // All domains
269
+ const all = await ep.domainScore('agent-v2');
270
+ console.log(all.domains.financial?.confidence); // "confident"
271
+ console.log(all.domains.code_execution?.confidence); // "provisional"
272
+
273
+ // Filtered to specific domains
274
+ const relevant = await ep.domainScore('agent-v2', ['financial', 'delegation']);
275
+ console.log(relevant.domains.financial?.completion_rate); // 98.1
276
+ console.log(relevant.domains.delegation?.dispute_rate); // 0.2
277
+ ```
278
+
279
+ ---
280
+
281
+ ### Install Preflight
282
+
283
+ #### `ep.installPreflight(entityId, policy?, context?)`
284
+
285
+ EP-SX: Software pre-action enforcement check (experimental). Use before installing any plugin, package, extension, MCP server, or marketplace app.
286
+
287
+ ```typescript
288
+ // MCP server
289
+ const mcp = await ep.installPreflight(
290
+ 'mcp-server-acme-v1',
291
+ 'mcp_server_safe_v1',
292
+ { host: 'claude-desktop', permission_class: 'bounded_external_access' },
293
+ );
294
+
295
+ console.log(mcp.decision); // "allow" | "review" | "deny"
296
+ console.log(mcp.confidence); // "confident"
297
+ console.log(mcp.reasons); // present for review/deny
298
+ console.log(mcp.software_meta?.publisher_verified); // true
299
+ console.log(mcp.software_meta?.permission_class); // "bounded_external_access"
300
+
301
+ if (mcp.decision === 'deny') throw new Error('Installation blocked by EP trust policy');
302
+ if (mcp.decision === 'review') console.warn('Manual review recommended before installing');
303
+
304
+ // npm package
305
+ const pkg = await ep.installPreflight(
306
+ 'npm:acme-build-plugin',
307
+ 'npm_buildtime_safe_v1',
308
+ { execution_mode: 'build_only' },
309
+ );
310
+
311
+ // Browser extension
312
+ const ext = await ep.installPreflight(
313
+ 'chrome_extension:acme-helper',
314
+ 'browser_extension_safe_v1',
315
+ { data_sensitivity: 'low' },
316
+ );
317
+
318
+ // GitHub App
319
+ const app = await ep.installPreflight(
320
+ 'github_app:acme/code-review',
321
+ 'github_private_repo_safe_v1',
322
+ { install_scope: 'private_repos' },
323
+ );
324
+ ```
325
+
326
+ ---
327
+
328
+ ### Entities
329
+
330
+ #### `ep.registerEntity(options)`
331
+
332
+ Register a new entity. Public endpoint — no API key required. Save the returned `api_key` securely; it will not be shown again.
333
+
334
+ ```typescript
335
+ const { entity, api_key } = await ep.registerEntity({
336
+ entityId: 'acme-payment-agent',
337
+ displayName: 'Acme Payment Agent',
338
+ entityType: 'agent',
339
+ description: 'Handles autonomous payment flows for Acme Corp.',
340
+ capabilities: ['payment', 'refund', 'dispute_resolution'],
341
+ });
342
+
343
+ console.log(entity.entity_id); // "acme-payment-agent"
344
+ console.log(api_key); // "ep_live_..." — store this securely!
345
+ ```
346
+
347
+ #### `ep.searchEntities(query, entityType?, minConfidence?)`
348
+
349
+ Search for entities by name, capability, or category.
350
+
351
+ ```typescript
352
+ const { entities } = await ep.searchEntities('payment', 'agent', 'confident');
353
+
354
+ for (const e of entities) {
355
+ console.log(`${e.display_name} (${e.entity_id}): ${e.confidence}`);
356
+ }
357
+ ```
358
+
359
+ #### `ep.leaderboard(limit?, entityType?)`
360
+
361
+ Get the leaderboard of top-trusted entities.
362
+
363
+ ```typescript
364
+ // Top 5 merchants
365
+ const { leaderboard } = await ep.leaderboard(5, 'merchant');
366
+ leaderboard.forEach(e => console.log(`#${e.rank} ${e.display_name} — ${e.confidence}`));
367
+ ```
368
+
369
+ ---
370
+
371
+ ### Receipts
372
+
373
+ #### `ep.submitReceipt(input)`
374
+
375
+ Submit a single transaction receipt. Requires an API key.
376
+
377
+ ```typescript
378
+ const { receipt } = await ep.submitReceipt({
379
+ entity_id: 'merchant-xyz',
380
+ transaction_ref: 'order-8821', // Required — must be unique per entity
381
+ transaction_type: 'purchase',
382
+ agent_behavior: 'completed', // Strongest signal — always set this
383
+ delivery_accuracy: 98,
384
+ product_accuracy: 95,
385
+ price_integrity: 100,
386
+ return_processing: 88,
387
+ claims: {
388
+ delivered: true,
389
+ on_time: true,
390
+ price_honored: true,
391
+ as_described: true,
392
+ },
393
+ context: {
394
+ category: 'electronics',
395
+ geo: 'US-NY',
396
+ value_band: 'medium',
397
+ },
398
+ });
399
+
400
+ console.log(receipt.receipt_id); // "ep_rcpt_..."
401
+ console.log(receipt.receipt_hash); // SHA-256 hash
402
+ ```
403
+
404
+ #### `ep.batchSubmit(receipts)`
405
+
406
+ Submit up to 50 receipts in a single atomic call. Partial success is possible.
407
+
408
+ ```typescript
409
+ const result = await ep.batchSubmit([
410
+ {
411
+ entity_id: 'merchant-a',
412
+ transaction_ref: 'tx-001',
413
+ transaction_type: 'purchase',
414
+ agent_behavior: 'completed',
415
+ },
416
+ {
417
+ entity_id: 'merchant-b',
418
+ transaction_ref: 'tx-002',
419
+ transaction_type: 'service',
420
+ agent_behavior: 'completed',
421
+ },
422
+ ]);
423
+
424
+ result.results.forEach(r => {
425
+ if (r.success) console.log(`${r.entity_id}: receipt ${r.receipt_id}`);
426
+ else console.error(`${r.entity_id}: ${r.error}`);
427
+ });
428
+ ```
429
+
430
+ #### `ep.confirmReceipt(receiptId, confirm)`
431
+
432
+ Bilateral confirmation — counterparty confirms or rejects a receipt within 48 hours. Confirmed receipts receive a higher provenance tier.
433
+
434
+ ```typescript
435
+ // Confirm as the counterparty
436
+ await ep.confirmReceipt('ep_rcpt_abc123', true);
437
+
438
+ // Reject (triggers dispute-like flow)
439
+ await ep.confirmReceipt('ep_rcpt_abc123', false);
440
+ ```
441
+
442
+ #### `ep.verifyReceipt(receiptId)`
443
+
444
+ Verify receipt hash integrity and Merkle root anchoring.
445
+
446
+ ```typescript
447
+ const { verified, anchored, receipt_hash } = await ep.verifyReceipt('ep_rcpt_abc123');
448
+
449
+ if (!verified) console.error('Receipt integrity check FAILED — possible tampering');
450
+ if (!anchored) console.log('Receipt not yet anchored — check back after next anchor cycle');
451
+ ```
452
+
453
+ ---
454
+
455
+ ### Disputes & Due Process
456
+
457
+ #### `ep.fileDispute(options)`
458
+
459
+ File a dispute against a receipt. Any affected party can challenge.
460
+
461
+ ```typescript
462
+ const dispute = await ep.fileDispute({
463
+ receiptId: 'ep_rcpt_abc123',
464
+ reason: 'inaccurate_signals', // See DisputeReason type for all options
465
+ description: 'Delivery accuracy was reported as 98 but item arrived damaged.',
466
+ evidence: { photo_url: 'https://cdn.example.com/damage-photo.jpg' },
467
+ });
468
+
469
+ console.log('Dispute ID:', dispute.dispute_id);
470
+ console.log('Respond by:', dispute.response_deadline); // 7-day window
471
+ ```
472
+
473
+ Valid `reason` values: `fraudulent_receipt` | `inaccurate_signals` | `identity_dispute` | `context_mismatch` | `duplicate_transaction` | `coerced_receipt` | `other`
474
+
475
+ #### `ep.disputeStatus(disputeId)`
476
+
477
+ Check dispute status. Public — transparency is a protocol value.
478
+
479
+ ```typescript
480
+ const dispute = await ep.disputeStatus('ep_disp_xyz789');
481
+
482
+ console.log(dispute.status); // "pending" | "responded" | "upheld" | "reversed" | "dismissed"
483
+ console.log(dispute.reason); // "inaccurate_signals"
484
+ console.log(dispute.entity?.entity_id); // "merchant-xyz"
485
+ console.log(dispute.response); // submitter's response (if provided)
486
+ console.log(dispute.resolution); // resolution decision (if resolved)
487
+ console.log(dispute.resolution_rationale);
488
+ ```
489
+
490
+ #### `ep.respondToDispute(options)`
491
+
492
+ Respond to a dispute filed against one of your receipts.
493
+
494
+ ```typescript
495
+ await ep.respondToDispute({
496
+ disputeId: 'ep_disp_xyz789',
497
+ response: 'The accuracy score reflects carrier handoff state, confirmed by tracking log.',
498
+ evidence: { tracking_log: 'https://carrier.example.com/track/8821' },
499
+ });
500
+ ```
501
+
502
+ #### `ep.withdrawDispute(disputeId)`
503
+
504
+ Withdraw an open dispute before resolution.
505
+
506
+ ```typescript
507
+ await ep.withdrawDispute('ep_disp_xyz789');
508
+ ```
509
+
510
+ #### `ep.appealDispute(options)`
511
+
512
+ Appeal a dispute resolution. Only dispute participants may appeal. The dispute must be in `upheld`, `reversed`, or `dismissed` state. Appeal decisions are final.
513
+
514
+ ```typescript
515
+ await ep.appealDispute({
516
+ disputeId: 'ep_disp_xyz789',
517
+ reason: 'The carrier log submitted in the response was from a different shipment.',
518
+ evidence: { corrected_manifest: 'https://...' },
519
+ });
520
+ ```
521
+
522
+ #### `ep.reportTrustIssue(options)`
523
+
524
+ Human appeal channel. No authentication required.
525
+
526
+ ```typescript
527
+ // No API key needed
528
+ const report = await ep.reportTrustIssue({
529
+ entityId: 'merchant-xyz',
530
+ reportType: 'harmed_by_trusted_entity',
531
+ description: 'Paid for an item marked delivered but never received. Order #8821.',
532
+ contactEmail: 'jane@example.com', // Optional — for EP follow-up
533
+ });
534
+
535
+ console.log(report.report_id); // "ep_report_..."
536
+ console.log(report._principle); // "Trust must never be more powerful than appeal."
537
+ ```
538
+
539
+ Valid `reportType` values: `wrongly_downgraded` | `harmed_by_trusted_entity` | `fraudulent_entity` | `inaccurate_profile` | `other`
540
+
541
+ ---
542
+
543
+ ### Delegation
544
+
545
+ #### `ep.createDelegation(options)`
546
+
547
+ Create a delegation record authorizing an agent to act on behalf of a principal.
548
+
549
+ ```typescript
550
+ const delegation = await ep.createDelegation({
551
+ principalId: 'ep_principal_acme',
552
+ agentEntityId: 'acme-payment-agent',
553
+ scope: ['purchase', 'refund'],
554
+ maxValueUsd: 1000,
555
+ expiresAt: '2026-12-31T23:59:59Z',
556
+ constraints: { require_confirmation_above_usd: 500 },
557
+ });
558
+
559
+ console.log('Delegation ID:', delegation.delegation_id);
560
+ console.log('Status:', delegation.status); // "active"
561
+ ```
562
+
563
+ #### `ep.verifyDelegation(delegationId, actionType?)`
564
+
565
+ Verify a delegation is valid and covers a specific action.
566
+
567
+ ```typescript
568
+ const result = await ep.verifyDelegation('ep_del_abc123', 'purchase');
569
+
570
+ console.log(result.valid); // true
571
+ console.log(result.action_permitted); // true
572
+ console.log(result.status); // "active"
573
+ console.log(result.expires_at); // "2026-12-31T23:59:59Z"
574
+
575
+ if (!result.valid) throw new Error(`Delegation invalid: ${result.reason}`);
576
+ ```
577
+
578
+ ---
579
+
580
+ ### Identity Continuity
581
+
582
+ #### `ep.principalLookup(principalId)`
583
+
584
+ Look up a principal — the enduring actor behind one or more entities.
585
+
586
+ ```typescript
587
+ const result = await ep.principalLookup('ep_principal_acme');
588
+
589
+ console.log(result.principal.display_name); // "Acme Corp"
590
+ console.log(result.principal.principal_type); // "organization"
591
+ console.log(result.principal.bootstrap_verified); // true
592
+
593
+ // Controlled entities
594
+ result.entities?.forEach(e => {
595
+ console.log(`${e.display_name} (${e.entity_type}): ${e.entity_id}`);
596
+ });
597
+
598
+ // Identity bindings (e.g. domain, GitHub org)
599
+ result.bindings?.forEach(b => {
600
+ console.log(`${b.binding_type}: ${b.binding_target} [${b.status}]`);
601
+ });
602
+
603
+ // Continuity history
604
+ result.continuity_claims?.forEach(c => {
605
+ console.log(`${c.old_entity_id} → ${c.new_entity_id} (${c.reason}) [${c.status}]`);
606
+ });
607
+ ```
608
+
609
+ #### `ep.lineage(entityId)`
610
+
611
+ View entity lineage — predecessors and successors. Use to detect reputation laundering.
612
+
613
+ ```typescript
614
+ const lineage = await ep.lineage('merchant-xyz');
615
+
616
+ // Check for suspicious predecessor gaps
617
+ if (lineage.predecessors?.some(p => p.status === 'disputed')) {
618
+ console.warn('Entity has disputed predecessor — investigate before transacting');
619
+ }
620
+
621
+ lineage.predecessors?.forEach(p => {
622
+ console.log(`← ${p.from} (${p.reason}) [${p.status}] transfer: ${p.transfer_policy}`);
623
+ });
624
+
625
+ lineage.successors?.forEach(s => {
626
+ console.log(`→ ${s.to} (${s.reason}) [${s.status}]`);
627
+ });
628
+ ```
629
+
630
+ ---
631
+
632
+ ### Policies
633
+
634
+ #### `ep.listPolicies()`
635
+
636
+ List all available trust policies.
637
+
638
+ ```typescript
639
+ const { policies } = await ep.listPolicies();
640
+
641
+ policies.forEach(p => {
642
+ console.log(`${p.name} [${p.family}]`);
643
+ console.log(` ${p.description}`);
644
+ if (p.min_confidence) console.log(` min confidence: ${p.min_confidence}`);
645
+ });
646
+ ```
647
+
648
+ ---
649
+
650
+ ### System
651
+
652
+ #### `ep.stats()`
653
+
654
+ Public proof metrics.
655
+
656
+ ```typescript
657
+ const stats = await ep.stats();
658
+ console.log(`${stats.total_entities} entities`);
659
+ console.log(`${stats.trust_policies} trust policies`);
660
+ console.log(`${stats.mcp_tools} MCP tools`);
661
+ ```
662
+
663
+ #### `ep.health()`
664
+
665
+ Health check.
666
+
667
+ ```typescript
668
+ const health = await ep.health();
669
+ console.log(health.status); // "ok"
670
+ ```
671
+
672
+ #### `ep.legacyScore(entityId)` (deprecated)
673
+
674
+ Returns the 0-100 legacy compatibility score. Prefer `trustProfile()` for all new code.
675
+
676
+ ```typescript
677
+ const { score } = await ep.legacyScore('merchant-xyz');
678
+ console.log(score); // 91
679
+ ```
680
+
681
+ ---
682
+
683
+ ## Error Handling
684
+
685
+ All methods throw `EPError` on failure. `EPError` extends `Error` with `status` (HTTP status code) and `code` (API error code).
686
+
687
+ ```typescript
688
+ import { EPClient, EPError } from '@emilia-protocol/sdk';
689
+
690
+ const ep = new EPClient({ apiKey: process.env.EP_API_KEY });
691
+
692
+ try {
693
+ const profile = await ep.trustProfile('unknown-entity');
694
+ } catch (err) {
695
+ if (err instanceof EPError) {
696
+ console.error(`EP error ${err.status}: ${err.message}`);
697
+ // err.status === 404 → entity not found
698
+ // err.status === 401 → missing or invalid API key
699
+ // err.status === 429 → rate limited
700
+ // err.code === 'timeout' → request timed out
701
+ // err.code === 'network_error' → network failure
702
+ } else {
703
+ throw err; // unexpected error — re-throw
704
+ }
705
+ }
706
+ ```
707
+
708
+ ### Common status codes
709
+
710
+ | Status | Meaning |
711
+ |---|---|
712
+ | `401` | Missing or invalid API key |
713
+ | `403` | Insufficient permissions for this operation |
714
+ | `404` | Entity, receipt, or dispute not found |
715
+ | `409` | Conflict (e.g. duplicate transaction_ref) |
716
+ | `422` | Validation error — check request body |
717
+ | `429` | Rate limited |
718
+
719
+ ---
720
+
721
+ ## TypeScript Usage
722
+
723
+ The SDK is fully typed. All types are exported from the package root.
724
+
725
+ ```typescript
726
+ import {
727
+ EPClient,
728
+ EPError,
729
+ // Enumerations
730
+ type EntityType,
731
+ type TrustPolicy,
732
+ type AgentBehavior,
733
+ type TransactionType,
734
+ type DisputeReason,
735
+ type TrustDomain,
736
+ type ConfidenceTier,
737
+ // Response types
738
+ type EntityTrustProfile,
739
+ type TrustEvaluation,
740
+ type TrustGateResult,
741
+ type InstallPreflightResult,
742
+ type Receipt,
743
+ type Dispute,
744
+ type DelegationRecord,
745
+ // Input types
746
+ type SubmitReceiptInput,
747
+ type TrustContext,
748
+ type EPClientOptions,
749
+ } from '@emilia-protocol/sdk';
750
+
751
+ // Type-safe client construction
752
+ const options: EPClientOptions = {
753
+ apiKey: process.env.EP_API_KEY,
754
+ timeout: 15_000,
755
+ };
756
+ const ep = new EPClient(options);
757
+
758
+ // Type-safe receipt submission
759
+ const input: SubmitReceiptInput = {
760
+ entity_id: 'merchant-xyz',
761
+ transaction_ref: `order-${Date.now()}`,
762
+ transaction_type: 'purchase',
763
+ agent_behavior: 'completed',
764
+ delivery_accuracy: 98,
765
+ };
766
+ const { receipt } = await ep.submitReceipt(input);
767
+
768
+ // Type-safe context
769
+ const context: TrustContext = {
770
+ category: 'electronics',
771
+ geo: 'US-CA',
772
+ value_band: 'high',
773
+ };
774
+ const evaluation = await ep.trustEvaluate('merchant-xyz', 'strict', context);
775
+
776
+ // Narrowing on confidence tier
777
+ function isHighConfidence(confidence: ConfidenceTier): boolean {
778
+ return confidence === 'confident' || confidence === 'emerging';
779
+ }
780
+ ```
781
+
782
+ ### Using with custom fetch (e.g. for testing)
783
+
784
+ ```typescript
785
+ import { EPClient } from '@emilia-protocol/sdk';
786
+
787
+ const mockFetch: typeof fetch = async (url, init) => {
788
+ // Return mock responses for testing
789
+ return new Response(JSON.stringify({ entity_id: 'test', current_confidence: 'confident' }));
790
+ };
791
+
792
+ const ep = new EPClient({ fetchImpl: mockFetch });
793
+ ```
794
+
795
+ ---
796
+
797
+ ## Links
798
+
799
+ - [emiliaprotocol.ai](https://emiliaprotocol.ai)
800
+ - [EP Core RFC](https://github.com/emiliaprotocol/emilia-protocol/blob/main/docs/EP-CORE-RFC.md)
801
+ - [OpenAPI Specification](https://github.com/emiliaprotocol/emilia-protocol/blob/main/openapi.yaml)
802
+ - [MCP Server](https://github.com/emiliaprotocol/emilia-protocol/tree/main/mcp-server)
803
+ - [Conformance Vectors](https://github.com/emiliaprotocol/emilia-protocol/tree/main/conformance)
804
+ - [Issues](https://github.com/emiliaprotocol/emilia-protocol/issues)
805
+
806
+ ---
807
+
808
+ ## License
809
+
810
+ Apache 2.0 — see [LICENSE](../../LICENSE).