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