@emilia-protocol/sdk 0.10.0 → 0.11.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/CHANGELOG.md +9 -0
- package/README.md +20 -44
- package/dist/client.d.ts +2 -30
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +44 -52
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +10 -747
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -487
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +15 -18
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +8 -6
- package/src/client.ts +44 -51
- package/src/index.ts +10 -1329
- package/src/types.ts +18 -19
package/src/index.ts
CHANGED
|
@@ -1,1332 +1,13 @@
|
|
|
1
|
-
/** EMILIA Protocol — Full SDK. Zero dependencies, native fetch. @license Apache-2.0 */
|
|
2
|
-
|
|
3
|
-
// -- Params -----------------------------------------------------------------
|
|
4
|
-
|
|
5
|
-
export interface EPClientOptions {
|
|
6
|
-
baseUrl?: string;
|
|
7
|
-
apiKey?: string;
|
|
8
|
-
timeout?: number;
|
|
9
|
-
retries?: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface Party {
|
|
13
|
-
entityRef: string;
|
|
14
|
-
role: 'initiator' | 'responder';
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface InitiateHandshakeParams {
|
|
18
|
-
mode: 'mutual' | 'one-way' | 'delegated';
|
|
19
|
-
policyId: string;
|
|
20
|
-
parties: Party[];
|
|
21
|
-
binding?: Record<string, unknown>;
|
|
22
|
-
interactionId?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface PresentParams {
|
|
26
|
-
partyRole: string;
|
|
27
|
-
presentationType: 'ep_trust_profile' | 'verifiable_credential' | 'attestation';
|
|
28
|
-
claims: Record<string, unknown>;
|
|
29
|
-
issuerRef?: string;
|
|
30
|
-
disclosureMode?: 'full' | 'selective' | 'zk';
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface GateParams {
|
|
34
|
-
entityId: string;
|
|
35
|
-
action: string;
|
|
36
|
-
policy?: 'strict' | 'standard' | 'permissive' | string;
|
|
37
|
-
handshakeId?: string;
|
|
38
|
-
valueUsd?: number;
|
|
39
|
-
delegationId?: string;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export interface ConsumeParams {
|
|
43
|
-
receiptData?: Record<string, unknown>;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export interface IssueChallengeParams {
|
|
47
|
-
entityId: string;
|
|
48
|
-
scope: string;
|
|
49
|
-
context?: Record<string, unknown>;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export interface AttestParams {
|
|
53
|
-
signature: string;
|
|
54
|
-
payload: Record<string, unknown>;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
export interface ConsumeSignoffParams {
|
|
58
|
-
action: string;
|
|
59
|
-
context?: Record<string, unknown>;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
export interface DenyChallengeParams {
|
|
63
|
-
reason?: string;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export interface RevokeSignoffOptions {
|
|
67
|
-
reason?: string;
|
|
68
|
-
force?: boolean;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export interface CreateDelegationParams {
|
|
72
|
-
delegatorId: string;
|
|
73
|
-
delegateeId: string;
|
|
74
|
-
scope: string;
|
|
75
|
-
policyId: string;
|
|
76
|
-
constraints?: Record<string, unknown>;
|
|
77
|
-
expiresAt?: string;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
export interface IssueCommitParams {
|
|
81
|
-
handshakeId: string;
|
|
82
|
-
action: string;
|
|
83
|
-
payload: Record<string, unknown>;
|
|
84
|
-
binding?: Record<string, unknown>;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// -- Eye Params -------------------------------------------------------------
|
|
88
|
-
|
|
89
|
-
export interface RecordObservationParams {
|
|
90
|
-
source_type: string;
|
|
91
|
-
source_ref: string;
|
|
92
|
-
subject_ref: string;
|
|
93
|
-
actor_ref: string;
|
|
94
|
-
action_type: string;
|
|
95
|
-
target_ref?: string;
|
|
96
|
-
issuer_ref?: string;
|
|
97
|
-
observation_type: string;
|
|
98
|
-
severity_hint: string;
|
|
99
|
-
evidence_hash?: string;
|
|
100
|
-
expires_at: string;
|
|
101
|
-
metadata?: Record<string, unknown>;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
export interface CheckActionParams {
|
|
105
|
-
subject_ref: string;
|
|
106
|
-
actor_ref: string;
|
|
107
|
-
action_type: string;
|
|
108
|
-
target_ref?: string;
|
|
109
|
-
issuer_ref?: string;
|
|
110
|
-
context_hash: string;
|
|
111
|
-
payload_hash?: string;
|
|
112
|
-
policy_class?: string;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
export interface CreateSuppressionParams {
|
|
116
|
-
scope_binding_hash: string;
|
|
117
|
-
reason_code: string;
|
|
118
|
-
justification: string;
|
|
119
|
-
expires_at: string;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// -- v1 Guard Params --------------------------------------------------------
|
|
123
|
-
|
|
124
|
-
export type GuardActionType =
|
|
125
|
-
| 'benefit_bank_account_change'
|
|
126
|
-
| 'benefit_address_change'
|
|
127
|
-
| 'caseworker_override'
|
|
128
|
-
| 'vendor_bank_account_change'
|
|
129
|
-
| 'beneficiary_creation'
|
|
130
|
-
| 'large_payment_release'
|
|
131
|
-
| 'ai_agent_payment_action';
|
|
132
|
-
|
|
133
|
-
export type GuardDecision = 'allow' | 'observe' | 'allow_with_signoff' | 'deny';
|
|
134
|
-
export type GuardEnforcementMode = 'observe' | 'warn' | 'enforce';
|
|
135
|
-
|
|
136
|
-
export interface GuardQuorumPolicy {
|
|
137
|
-
mode?: 'threshold' | 'all';
|
|
138
|
-
required: number;
|
|
139
|
-
approvers: Array<{ role: string; approver: string }>;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export interface CreateTrustReceiptParams {
|
|
143
|
-
organizationId?: string;
|
|
144
|
-
actionType: GuardActionType | string;
|
|
145
|
-
targetResourceId: string;
|
|
146
|
-
policyId?: string;
|
|
147
|
-
enforcementMode?: GuardEnforcementMode;
|
|
148
|
-
beforeState?: Record<string, unknown>;
|
|
149
|
-
afterState?: Record<string, unknown>;
|
|
150
|
-
targetChangedFields?: string[];
|
|
151
|
-
amount?: number;
|
|
152
|
-
currency?: string;
|
|
153
|
-
riskFlags?: string[];
|
|
154
|
-
actorRole?: string;
|
|
155
|
-
actorDepartment?: string;
|
|
156
|
-
businessHours?: boolean;
|
|
157
|
-
velocitySameActor24h?: number;
|
|
158
|
-
priorDenialsActor30d?: number;
|
|
159
|
-
priorChangesTarget30d?: number;
|
|
160
|
-
destinationAgeDays?: number;
|
|
161
|
-
quorumPolicy?: GuardQuorumPolicy;
|
|
162
|
-
metadata?: Record<string, unknown>;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export interface TrustReceipt {
|
|
166
|
-
receipt_id: string;
|
|
167
|
-
decision: GuardDecision;
|
|
168
|
-
observed_decision?: GuardDecision | null;
|
|
169
|
-
policy_id: string;
|
|
170
|
-
policy_hash: string;
|
|
171
|
-
action_hash: string;
|
|
172
|
-
before_state_hash?: string | null;
|
|
173
|
-
after_state_hash?: string | null;
|
|
174
|
-
nonce: string;
|
|
175
|
-
expires_at: string;
|
|
176
|
-
signoff_required: boolean;
|
|
177
|
-
signoff_request_id?: string | null;
|
|
178
|
-
risk_flags?: string[];
|
|
179
|
-
receipt_status: string;
|
|
180
|
-
enforcement_mode: string;
|
|
181
|
-
reasons?: string[];
|
|
182
|
-
canonical_action: Record<string, unknown>;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
export interface TrustReceiptState {
|
|
186
|
-
receipt_id: string;
|
|
187
|
-
organization_id: string;
|
|
188
|
-
action_type: string;
|
|
189
|
-
decision: GuardDecision;
|
|
190
|
-
enforcement_mode: string;
|
|
191
|
-
policy_id: string;
|
|
192
|
-
policy_hash: string;
|
|
193
|
-
action_hash: string;
|
|
194
|
-
expires_at: string;
|
|
195
|
-
signoff_required: boolean;
|
|
196
|
-
receipt_status: string;
|
|
197
|
-
signoff_key_class?: string | null;
|
|
198
|
-
timeline_event_count: number;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
export interface RequestSignoffParams {
|
|
202
|
-
receiptId: string;
|
|
203
|
-
approverId?: string;
|
|
204
|
-
expiresInMinutes?: number;
|
|
205
|
-
comment?: string;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
export interface SignoffRequest {
|
|
209
|
-
signoff_id?: string;
|
|
210
|
-
receipt_id: string;
|
|
211
|
-
action_hash: string;
|
|
212
|
-
initiator_id: string;
|
|
213
|
-
approver_id?: string;
|
|
214
|
-
expires_at: string;
|
|
215
|
-
status: string;
|
|
216
|
-
quorum?: { mode: string; required: number; count: number };
|
|
217
|
-
signoffs?: Array<{ signoff_id: string; role?: string; approver_id: string }>;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
export interface ConsumeTrustReceiptResult {
|
|
221
|
-
receipt_id: string;
|
|
222
|
-
status: string;
|
|
223
|
-
consumed_at: string;
|
|
224
|
-
consumed_by_system: string;
|
|
225
|
-
execution_reference_id?: string | null;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export interface ExecutionAttestation {
|
|
229
|
-
receipt_id: string;
|
|
230
|
-
status: string;
|
|
231
|
-
binding_status: string;
|
|
232
|
-
executed_action_hash: string;
|
|
233
|
-
approved_action_hash: string;
|
|
234
|
-
execution_integrity: Record<string, unknown>;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
export interface TrustReceiptEvidence {
|
|
238
|
-
document: Record<string, unknown> | null;
|
|
239
|
-
public_key: string | null;
|
|
240
|
-
signed: boolean;
|
|
241
|
-
verify_with: string;
|
|
242
|
-
receipt_id: string;
|
|
243
|
-
organization_id: string;
|
|
244
|
-
issued_at: string;
|
|
245
|
-
expires_at: string;
|
|
246
|
-
schema_version: string;
|
|
247
|
-
[key: string]: unknown;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
export interface RequireReceiptParams extends CreateTrustReceiptParams {
|
|
251
|
-
executingSystem: string;
|
|
252
|
-
executionReferenceId?: string;
|
|
253
|
-
approverId?: string;
|
|
254
|
-
signoffComment?: string;
|
|
255
|
-
signoffExpiresInMinutes?: number;
|
|
256
|
-
onSignoffRequired?: (ctx: { client: EPClient; receipt: TrustReceipt; signoff?: SignoffRequest }) => Promise<void | boolean | { approved?: boolean }>;
|
|
257
|
-
executedAction?: Record<string, unknown> | ((ctx: { receipt: TrustReceipt; result: unknown }) => Record<string, unknown>);
|
|
258
|
-
executionId?: string | ((result: unknown) => string | undefined);
|
|
259
|
-
fetchEvidence?: boolean;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
export interface RequireReceiptResult<T> {
|
|
263
|
-
result: T;
|
|
264
|
-
receipt: TrustReceipt;
|
|
265
|
-
signoff?: SignoffRequest;
|
|
266
|
-
consume: ConsumeTrustReceiptResult;
|
|
267
|
-
execution: ExecutionAttestation;
|
|
268
|
-
evidence?: TrustReceiptEvidence;
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// -- Eye Responses ----------------------------------------------------------
|
|
272
|
-
|
|
273
|
-
export interface ObservationResponse {
|
|
274
|
-
observation_id: string;
|
|
275
|
-
observation_type: string;
|
|
276
|
-
severity_hint: string;
|
|
277
|
-
observed_at: string;
|
|
278
|
-
expires_at: string;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
export interface AdvisoryResponse {
|
|
282
|
-
advisory_id: string;
|
|
283
|
-
status: string;
|
|
284
|
-
reason_codes: string[];
|
|
285
|
-
recommended_policy_action: string;
|
|
286
|
-
evidence_refs: string[];
|
|
287
|
-
scope_binding_hash: string;
|
|
288
|
-
issued_at: string;
|
|
289
|
-
expires_at: string;
|
|
290
|
-
version: number;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
export interface SuppressionResponse {
|
|
294
|
-
suppression_id: string;
|
|
295
|
-
status: string;
|
|
296
|
-
created_at: string;
|
|
297
|
-
expires_at: string;
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
// -- Cloud Params -----------------------------------------------------------
|
|
301
|
-
|
|
302
|
-
export interface SignoffFilters {
|
|
303
|
-
entityId?: string;
|
|
304
|
-
scope?: string;
|
|
305
|
-
status?: string;
|
|
306
|
-
limit?: number;
|
|
307
|
-
offset?: number;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
export interface DateRange {
|
|
311
|
-
from?: string;
|
|
312
|
-
to?: string;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export interface EscalateSignoffParams {
|
|
316
|
-
challengeId: string;
|
|
317
|
-
escalateTo: string;
|
|
318
|
-
reason: string;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
export interface NotifySignoffParams {
|
|
322
|
-
challengeId: string;
|
|
323
|
-
channel: string;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
export interface SearchEventsParams {
|
|
327
|
-
query: string;
|
|
328
|
-
filters?: Record<string, unknown>;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export interface ExportAuditParams {
|
|
332
|
-
format?: 'json' | 'csv' | 'pdf';
|
|
333
|
-
dateRange?: DateRange;
|
|
334
|
-
entityId?: string;
|
|
335
|
-
eventTypes?: string[];
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
export interface GetAuditReportParams {
|
|
339
|
-
reportType: string;
|
|
340
|
-
dateRange: DateRange;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
export interface SimulatePolicyParams {
|
|
344
|
-
policyId: string;
|
|
345
|
-
context: Record<string, unknown>;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
export interface RolloutPolicyParams {
|
|
349
|
-
policyId: string;
|
|
350
|
-
/** Policy version number to roll out (resolved against handshake_policies). */
|
|
351
|
-
version: number;
|
|
352
|
-
/** Target environment, e.g. "production" or "staging". */
|
|
353
|
-
environment: string;
|
|
354
|
-
strategy?: 'immediate' | 'canary';
|
|
355
|
-
/** Traffic percentage (1–99) for canary rollouts. */
|
|
356
|
-
canaryPct?: number;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
export interface DiffPolicyVersionsParams {
|
|
360
|
-
policyId: string;
|
|
361
|
-
/** First version number to compare. */
|
|
362
|
-
v1: number;
|
|
363
|
-
/** Second version number to compare. */
|
|
364
|
-
v2: number;
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// -- Responses --------------------------------------------------------------
|
|
368
|
-
|
|
369
|
-
export interface Policy {
|
|
370
|
-
name: string;
|
|
371
|
-
family: string;
|
|
372
|
-
description: string;
|
|
373
|
-
minConfidence?: string;
|
|
374
|
-
minScore?: number;
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
export interface Handshake {
|
|
378
|
-
id: string;
|
|
379
|
-
status: string;
|
|
380
|
-
mode: string;
|
|
381
|
-
policyId: string;
|
|
382
|
-
parties: Party[];
|
|
383
|
-
createdAt: string;
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
export interface Presentation {
|
|
387
|
-
presentationId: string;
|
|
388
|
-
partyRole: string;
|
|
389
|
-
status: string;
|
|
390
|
-
createdAt: string;
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
export interface VerificationResult {
|
|
394
|
-
handshakeId: string;
|
|
395
|
-
result: 'accepted' | 'rejected' | 'partial';
|
|
396
|
-
reasonCodes: string[];
|
|
397
|
-
evaluatedAt: string;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
export interface GateResult {
|
|
401
|
-
decision: 'allow' | 'deny' | 'review';
|
|
402
|
-
commitRef?: string;
|
|
403
|
-
reasons: string[];
|
|
404
|
-
appealPath?: string;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
export interface SignoffChallenge {
|
|
408
|
-
challengeId: string;
|
|
409
|
-
entityId: string;
|
|
410
|
-
scope: string;
|
|
411
|
-
nonce: string;
|
|
412
|
-
expiresAt: string;
|
|
413
|
-
}
|
|
414
|
-
|
|
415
|
-
export interface SignoffAttestation {
|
|
416
|
-
attestationId: string;
|
|
417
|
-
challengeId: string;
|
|
418
|
-
status: 'valid' | 'invalid' | 'expired';
|
|
419
|
-
signoffId?: string;
|
|
420
|
-
createdAt: string;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export interface SignoffConsumption {
|
|
424
|
-
signoffId: string;
|
|
425
|
-
consumed: boolean;
|
|
426
|
-
action: string;
|
|
427
|
-
consumedAt?: string;
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
export interface Consumption {
|
|
431
|
-
handshakeId: string;
|
|
432
|
-
consumed: boolean;
|
|
433
|
-
receiptId?: string;
|
|
434
|
-
consumedAt?: string;
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
export interface RevokeResult {
|
|
438
|
-
id: string;
|
|
439
|
-
revoked: boolean;
|
|
440
|
-
revokedAt: string;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
export interface DenyResult {
|
|
444
|
-
challengeId: string;
|
|
445
|
-
denied: boolean;
|
|
446
|
-
reason?: string;
|
|
447
|
-
deniedAt: string;
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
export interface Delegation {
|
|
451
|
-
delegationId: string;
|
|
452
|
-
delegatorId: string;
|
|
453
|
-
delegateeId: string;
|
|
454
|
-
scope: string;
|
|
455
|
-
policyId: string;
|
|
456
|
-
status: string;
|
|
457
|
-
constraints?: Record<string, unknown>;
|
|
458
|
-
createdAt: string;
|
|
459
|
-
expiresAt?: string;
|
|
460
|
-
}
|
|
461
|
-
|
|
462
|
-
export interface DelegationVerification {
|
|
463
|
-
delegationId: string;
|
|
464
|
-
valid: boolean;
|
|
465
|
-
status: string;
|
|
466
|
-
reasonCodes: string[];
|
|
467
|
-
verifiedAt: string;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
export interface Commit {
|
|
471
|
-
commitId: string;
|
|
472
|
-
handshakeId: string;
|
|
473
|
-
action: string;
|
|
474
|
-
status: string;
|
|
475
|
-
payload: Record<string, unknown>;
|
|
476
|
-
createdAt: string;
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
export interface CommitVerification {
|
|
480
|
-
commitId: string;
|
|
481
|
-
valid: boolean;
|
|
482
|
-
status: string;
|
|
483
|
-
reasonCodes: string[];
|
|
484
|
-
verifiedAt: string;
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// -- Cloud Responses --------------------------------------------------------
|
|
488
|
-
|
|
489
|
-
export interface PendingSignoff {
|
|
490
|
-
challengeId: string;
|
|
491
|
-
entityId: string;
|
|
492
|
-
scope: string;
|
|
493
|
-
status: string;
|
|
494
|
-
createdAt: string;
|
|
495
|
-
expiresAt: string;
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
export interface PendingSignoffsResponse {
|
|
499
|
-
items: PendingSignoff[];
|
|
500
|
-
total: number;
|
|
501
|
-
offset: number;
|
|
502
|
-
limit: number;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
export interface SignoffQueueItem {
|
|
506
|
-
challengeId: string;
|
|
507
|
-
entityId: string;
|
|
508
|
-
scope: string;
|
|
509
|
-
priority: string;
|
|
510
|
-
status: string;
|
|
511
|
-
createdAt: string;
|
|
512
|
-
expiresAt: string;
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
export interface SignoffQueueResponse {
|
|
516
|
-
items: SignoffQueueItem[];
|
|
517
|
-
total: number;
|
|
518
|
-
offset: number;
|
|
519
|
-
limit: number;
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
export interface SignoffDashboard {
|
|
523
|
-
pending: number;
|
|
524
|
-
approved: number;
|
|
525
|
-
denied: number;
|
|
526
|
-
expired: number;
|
|
527
|
-
averageResponseTime: number;
|
|
528
|
-
recentActivity: DashboardActivity[];
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
export interface DashboardActivity {
|
|
532
|
-
challengeId: string;
|
|
533
|
-
action: string;
|
|
534
|
-
entityId: string;
|
|
535
|
-
timestamp: string;
|
|
536
|
-
}
|
|
537
|
-
|
|
538
|
-
export interface SignoffAnalytics {
|
|
539
|
-
totalChallenges: number;
|
|
540
|
-
approvalRate: number;
|
|
541
|
-
averageResponseTime: number;
|
|
542
|
-
byScope: Record<string, number>;
|
|
543
|
-
timeseries: AnalyticsDataPoint[];
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
export interface AnalyticsDataPoint {
|
|
547
|
-
timestamp: string;
|
|
548
|
-
count: number;
|
|
549
|
-
approved: number;
|
|
550
|
-
denied: number;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
export interface EscalationResult {
|
|
554
|
-
challengeId: string;
|
|
555
|
-
escalatedTo: string;
|
|
556
|
-
escalatedAt: string;
|
|
557
|
-
status: string;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
export interface NotificationResult {
|
|
561
|
-
challengeId: string;
|
|
562
|
-
channel: string;
|
|
563
|
-
sent: boolean;
|
|
564
|
-
sentAt: string;
|
|
565
|
-
}
|
|
566
|
-
|
|
567
|
-
export interface AuditEvent {
|
|
568
|
-
eventId: string;
|
|
569
|
-
type: string;
|
|
570
|
-
entityId: string;
|
|
571
|
-
action: string;
|
|
572
|
-
metadata: Record<string, unknown>;
|
|
573
|
-
timestamp: string;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
export interface SearchEventsResponse {
|
|
577
|
-
items: AuditEvent[];
|
|
578
|
-
total: number;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
export interface EventTimeline {
|
|
582
|
-
handshakeId: string;
|
|
583
|
-
events: AuditEvent[];
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
export interface ExportAuditResult {
|
|
587
|
-
exportId: string;
|
|
588
|
-
format: string;
|
|
589
|
-
status: string;
|
|
590
|
-
downloadUrl?: string;
|
|
591
|
-
createdAt: string;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
export interface AuditReport {
|
|
595
|
-
reportType: string;
|
|
596
|
-
dateRange: DateRange;
|
|
597
|
-
summary: Record<string, unknown>;
|
|
598
|
-
items: AuditEvent[];
|
|
599
|
-
generatedAt: string;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
export interface IntegrityCheckResult {
|
|
603
|
-
healthy: boolean;
|
|
604
|
-
checks: IntegrityCheck[];
|
|
605
|
-
checkedAt: string;
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
export interface IntegrityCheck {
|
|
609
|
-
name: string;
|
|
610
|
-
status: 'pass' | 'fail' | 'warn';
|
|
611
|
-
message?: string;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
export interface PolicySimulationResult {
|
|
615
|
-
policyId: string;
|
|
616
|
-
decision: 'allow' | 'deny' | 'review';
|
|
617
|
-
reasons: string[];
|
|
618
|
-
evaluatedAt: string;
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
export interface PolicyRolloutResult {
|
|
622
|
-
rollout_id: string;
|
|
623
|
-
/** handshake_policies policy_id of the rolled-out version row. */
|
|
624
|
-
policy_id: string;
|
|
625
|
-
policy_key: string;
|
|
626
|
-
version: number;
|
|
627
|
-
environment: string;
|
|
628
|
-
strategy: string;
|
|
629
|
-
status: string;
|
|
630
|
-
canary_pct: number | null;
|
|
631
|
-
initiated_at: string;
|
|
632
|
-
tenant_id: string;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
1
|
/**
|
|
636
|
-
*
|
|
637
|
-
*
|
|
2
|
+
* EMILIA Protocol TypeScript SDK.
|
|
3
|
+
*
|
|
4
|
+
* The package root intentionally re-exports the single supported client
|
|
5
|
+
* implementation. Keeping the entry point as a barrel prevents the public
|
|
6
|
+
* package contract from drifting away from the client exercised by the SDK
|
|
7
|
+
* tests and documented in the README.
|
|
8
|
+
*
|
|
9
|
+
* @license Apache-2.0
|
|
638
10
|
*/
|
|
639
|
-
export interface PolicyVersion {
|
|
640
|
-
policy_id: string;
|
|
641
|
-
policy_key: string;
|
|
642
|
-
version: number;
|
|
643
|
-
name: string;
|
|
644
|
-
mode: string;
|
|
645
|
-
status: string;
|
|
646
|
-
rules: Record<string, unknown>;
|
|
647
|
-
created_at: string;
|
|
648
|
-
updated_at: string;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
export interface PolicyVersionsResult {
|
|
652
|
-
policy_id: string;
|
|
653
|
-
policy_key: string;
|
|
654
|
-
versions: PolicyVersion[];
|
|
655
|
-
count: number;
|
|
656
|
-
tenant_id: string;
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
/** A single classified field change between two policy versions' rules. */
|
|
660
|
-
export interface PolicyChange {
|
|
661
|
-
path: string;
|
|
662
|
-
before: unknown;
|
|
663
|
-
after: unknown;
|
|
664
|
-
risk: 'loosening' | 'tightening' | 'neutral';
|
|
665
|
-
rationale: string;
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
/** Semantic diff of v1.rules vs v2.rules. */
|
|
669
|
-
export interface PolicyRulesDiff {
|
|
670
|
-
changes: PolicyChange[];
|
|
671
|
-
risk: 'loosening' | 'tightening' | 'neutral';
|
|
672
|
-
summary: {
|
|
673
|
-
loosening: number;
|
|
674
|
-
tightening: number;
|
|
675
|
-
neutral: number;
|
|
676
|
-
};
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
export interface PolicyDiff {
|
|
680
|
-
policy_id: string;
|
|
681
|
-
policy_key: string;
|
|
682
|
-
/** The lower-numbered handshake_policies version row. */
|
|
683
|
-
v1: PolicyVersion;
|
|
684
|
-
/** The higher-numbered handshake_policies version row. */
|
|
685
|
-
v2: PolicyVersion;
|
|
686
|
-
diff: PolicyRulesDiff;
|
|
687
|
-
tenant_id: string;
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
// -- Error ------------------------------------------------------------------
|
|
691
|
-
|
|
692
|
-
export class EPError extends Error {
|
|
693
|
-
constructor(
|
|
694
|
-
message: string,
|
|
695
|
-
public readonly status?: number,
|
|
696
|
-
public readonly code?: string,
|
|
697
|
-
) {
|
|
698
|
-
super(message);
|
|
699
|
-
this.name = 'EPError';
|
|
700
|
-
Object.setPrototypeOf(this, new.target.prototype);
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
// -- Cloud Client -----------------------------------------------------------
|
|
705
|
-
|
|
706
|
-
export class EPCloudClient {
|
|
707
|
-
/** @internal */
|
|
708
|
-
constructor(private readonly _request: <T>(method: string, path: string, body?: unknown, auth?: boolean) => Promise<T>) {}
|
|
709
|
-
|
|
710
|
-
/** Get pending signoffs, optionally filtered by entity, scope, or status. */
|
|
711
|
-
async getPendingSignoffs(filters?: SignoffFilters): Promise<PendingSignoffsResponse> {
|
|
712
|
-
const qs = this._buildQs(filters);
|
|
713
|
-
return this._request<PendingSignoffsResponse>('GET', `/api/cloud/signoffs/pending${qs}`, undefined, true);
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
/** Get the signoff queue with optional filtering. */
|
|
717
|
-
async getSignoffQueue(filters?: SignoffFilters): Promise<SignoffQueueResponse> {
|
|
718
|
-
const qs = this._buildQs(filters);
|
|
719
|
-
return this._request<SignoffQueueResponse>('GET', `/api/cloud/signoffs/queue${qs}`, undefined, true);
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
/** Get a dashboard summary of signoff activity over a date range. */
|
|
723
|
-
async getSignoffDashboard(dateRange?: DateRange): Promise<SignoffDashboard> {
|
|
724
|
-
const qs = this._buildDateRangeQs(dateRange);
|
|
725
|
-
return this._request<SignoffDashboard>('GET', `/api/cloud/signoffs/dashboard${qs}`, undefined, true);
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
/** Get analytics for signoff activity with optional granularity. */
|
|
729
|
-
async getSignoffAnalytics(dateRange?: DateRange, granularity?: 'hour' | 'day' | 'week' | 'month'): Promise<SignoffAnalytics> {
|
|
730
|
-
const params: Record<string, string> = {};
|
|
731
|
-
if (dateRange?.from) params['from'] = dateRange.from;
|
|
732
|
-
if (dateRange?.to) params['to'] = dateRange.to;
|
|
733
|
-
if (granularity) params['granularity'] = granularity;
|
|
734
|
-
const qs = this._toQs(params);
|
|
735
|
-
return this._request<SignoffAnalytics>('GET', `/api/cloud/signoffs/analytics${qs}`, undefined, true);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/** Escalate a signoff challenge to another entity. */
|
|
739
|
-
async escalateSignoff(challengeId: string, escalateTo: string, reason: string): Promise<EscalationResult> {
|
|
740
|
-
return this._request<EscalationResult>('POST', `/api/cloud/signoffs/${encodeURIComponent(challengeId)}/escalate`, {
|
|
741
|
-
escalateTo,
|
|
742
|
-
reason,
|
|
743
|
-
}, true);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
/** Send a notification about a signoff challenge via the specified channel. */
|
|
747
|
-
async notifySignoff(challengeId: string, channel: string): Promise<NotificationResult> {
|
|
748
|
-
return this._request<NotificationResult>('POST', `/api/cloud/signoffs/${encodeURIComponent(challengeId)}/notify`, {
|
|
749
|
-
channel,
|
|
750
|
-
}, true);
|
|
751
|
-
}
|
|
752
|
-
|
|
753
|
-
/** Search audit events by query string and optional filters. */
|
|
754
|
-
async searchEvents(query: string, filters?: Record<string, unknown>): Promise<SearchEventsResponse> {
|
|
755
|
-
return this._request<SearchEventsResponse>('POST', '/api/cloud/events/search', {
|
|
756
|
-
query,
|
|
757
|
-
filters,
|
|
758
|
-
}, true);
|
|
759
|
-
}
|
|
760
|
-
|
|
761
|
-
/** Get a chronological timeline of events for a specific handshake. */
|
|
762
|
-
async getEventTimeline(handshakeId: string): Promise<EventTimeline> {
|
|
763
|
-
return this._request<EventTimeline>('GET', `/api/cloud/events/timeline/${encodeURIComponent(handshakeId)}`, undefined, true);
|
|
764
|
-
}
|
|
765
|
-
|
|
766
|
-
/** Export audit data in the specified format. */
|
|
767
|
-
async exportAudit(params: ExportAuditParams): Promise<ExportAuditResult> {
|
|
768
|
-
return this._request<ExportAuditResult>('POST', '/api/cloud/audit/export', params, true);
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
/** Generate an audit report for the given type and date range. */
|
|
772
|
-
async getAuditReport(reportType: string, dateRange: DateRange): Promise<AuditReport> {
|
|
773
|
-
return this._request<AuditReport>('POST', '/api/cloud/audit/report', {
|
|
774
|
-
reportType,
|
|
775
|
-
dateRange,
|
|
776
|
-
}, true);
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
/** Run an integrity check on the protocol data store. */
|
|
780
|
-
async checkIntegrity(): Promise<IntegrityCheckResult> {
|
|
781
|
-
return this._request<IntegrityCheckResult>('POST', '/api/cloud/integrity/check', undefined, true);
|
|
782
|
-
}
|
|
783
|
-
|
|
784
|
-
/** Simulate a policy against a hypothetical context without persisting any state. */
|
|
785
|
-
async simulatePolicy(policyId: string, context: Record<string, unknown>): Promise<PolicySimulationResult> {
|
|
786
|
-
return this._request<PolicySimulationResult>('POST', `/api/cloud/policies/${encodeURIComponent(policyId)}/simulate`, {
|
|
787
|
-
context,
|
|
788
|
-
}, true);
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
/**
|
|
792
|
-
* Roll out a specific policy version to an environment. The version is
|
|
793
|
-
* resolved against handshake_policies by the policy's policy_key. Immediate
|
|
794
|
-
* rollouts supersede the prior active rollout for that (policy_key,
|
|
795
|
-
* environment); canary rollouts coexist (canaryPct in 1–99).
|
|
796
|
-
*/
|
|
797
|
-
async rolloutPolicy(
|
|
798
|
-
policyId: string,
|
|
799
|
-
version: number,
|
|
800
|
-
environment: string,
|
|
801
|
-
strategy: 'immediate' | 'canary' = 'immediate',
|
|
802
|
-
canaryPct?: number,
|
|
803
|
-
): Promise<PolicyRolloutResult> {
|
|
804
|
-
return this._request<PolicyRolloutResult>('POST', `/api/cloud/policies/${encodeURIComponent(policyId)}/rollout`, {
|
|
805
|
-
version,
|
|
806
|
-
environment,
|
|
807
|
-
strategy,
|
|
808
|
-
...(strategy === 'canary' && canaryPct !== undefined ? { canary_pct: canaryPct } : {}),
|
|
809
|
-
}, true);
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* List all versions of a policy. Versions are the handshake_policies rows
|
|
814
|
-
* sharing the policy's policy_key, returned newest-first inside an envelope.
|
|
815
|
-
*/
|
|
816
|
-
async getPolicyVersions(policyId: string): Promise<PolicyVersionsResult> {
|
|
817
|
-
return this._request<PolicyVersionsResult>('GET', `/api/cloud/policies/${encodeURIComponent(policyId)}/versions`, undefined, true);
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
/**
|
|
821
|
-
* Diff two versions of a policy to see what changed between their rules.
|
|
822
|
-
* v1 and v2 are version numbers; the response includes both version rows and
|
|
823
|
-
* a semantic diff classified as loosening / tightening / neutral.
|
|
824
|
-
*/
|
|
825
|
-
async diffPolicyVersions(policyId: string, v1: number, v2: number): Promise<PolicyDiff> {
|
|
826
|
-
const qs = this._toQs({ v1: String(v1), v2: String(v2) });
|
|
827
|
-
return this._request<PolicyDiff>('GET', `/api/cloud/policies/${encodeURIComponent(policyId)}/diff${qs}`, undefined, true);
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
/** @internal Build query string from SignoffFilters. */
|
|
831
|
-
private _buildQs(filters?: SignoffFilters): string {
|
|
832
|
-
if (!filters) return '';
|
|
833
|
-
const params: Record<string, string> = {};
|
|
834
|
-
if (filters.entityId) params['entityId'] = filters.entityId;
|
|
835
|
-
if (filters.scope) params['scope'] = filters.scope;
|
|
836
|
-
if (filters.status) params['status'] = filters.status;
|
|
837
|
-
if (filters.limit !== undefined) params['limit'] = String(filters.limit);
|
|
838
|
-
if (filters.offset !== undefined) params['offset'] = String(filters.offset);
|
|
839
|
-
return this._toQs(params);
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
/** @internal Build query string from DateRange. */
|
|
843
|
-
private _buildDateRangeQs(dateRange?: DateRange): string {
|
|
844
|
-
if (!dateRange) return '';
|
|
845
|
-
const params: Record<string, string> = {};
|
|
846
|
-
if (dateRange.from) params['from'] = dateRange.from;
|
|
847
|
-
if (dateRange.to) params['to'] = dateRange.to;
|
|
848
|
-
return this._toQs(params);
|
|
849
|
-
}
|
|
850
|
-
|
|
851
|
-
/** @internal Convert key-value pairs to a query string. */
|
|
852
|
-
private _toQs(params: Record<string, string>): string {
|
|
853
|
-
const entries = Object.entries(params).filter(([, v]) => v !== undefined && v !== '');
|
|
854
|
-
if (entries.length === 0) return '';
|
|
855
|
-
return '?' + entries.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`).join('&');
|
|
856
|
-
}
|
|
857
|
-
}
|
|
858
|
-
|
|
859
|
-
// -- Client -----------------------------------------------------------------
|
|
860
|
-
|
|
861
|
-
function trustReceiptBody(params: CreateTrustReceiptParams): Record<string, unknown> {
|
|
862
|
-
return {
|
|
863
|
-
organization_id: params.organizationId,
|
|
864
|
-
action_type: params.actionType,
|
|
865
|
-
target_resource_id: params.targetResourceId,
|
|
866
|
-
policy_id: params.policyId,
|
|
867
|
-
enforcement_mode: params.enforcementMode,
|
|
868
|
-
before_state: params.beforeState,
|
|
869
|
-
after_state: params.afterState,
|
|
870
|
-
target_changed_fields: params.targetChangedFields,
|
|
871
|
-
amount: params.amount,
|
|
872
|
-
currency: params.currency,
|
|
873
|
-
risk_flags: params.riskFlags,
|
|
874
|
-
actor_role: params.actorRole,
|
|
875
|
-
actor_department: params.actorDepartment,
|
|
876
|
-
business_hours: params.businessHours,
|
|
877
|
-
velocity_same_actor_24h: params.velocitySameActor24h,
|
|
878
|
-
prior_denials_actor_30d: params.priorDenialsActor30d,
|
|
879
|
-
prior_changes_target_30d: params.priorChangesTarget30d,
|
|
880
|
-
destination_age_days: params.destinationAgeDays,
|
|
881
|
-
quorum_policy: params.quorumPolicy,
|
|
882
|
-
metadata: params.metadata,
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
export class EPClient {
|
|
887
|
-
private readonly baseUrl: string;
|
|
888
|
-
private readonly apiKey: string;
|
|
889
|
-
private readonly timeout: number;
|
|
890
|
-
private readonly retries: number;
|
|
891
|
-
|
|
892
|
-
/** Cloud-specific endpoints (dashboards, analytics, audit, policy management). */
|
|
893
|
-
public readonly cloud: EPCloudClient;
|
|
894
|
-
|
|
895
|
-
constructor(options: EPClientOptions = {}) {
|
|
896
|
-
const env = typeof process !== 'undefined' && process.env ? process.env : {};
|
|
897
|
-
// Trim trailing slashes without a regex — avoids the polynomial-backtracking
|
|
898
|
-
// CodeQL flags on /\/+$/ for long all-slash inputs.
|
|
899
|
-
const rawBase = options.baseUrl ?? env.EP_BASE_URL ?? 'https://emiliaprotocol.ai';
|
|
900
|
-
let baseEnd = rawBase.length;
|
|
901
|
-
while (baseEnd > 0 && rawBase.charCodeAt(baseEnd - 1) === 47 /* '/' */) baseEnd--;
|
|
902
|
-
this.baseUrl = rawBase.slice(0, baseEnd);
|
|
903
|
-
this.apiKey = options.apiKey ?? env.EP_API_KEY ?? '';
|
|
904
|
-
this.timeout = options.timeout ?? 10_000;
|
|
905
|
-
this.retries = options.retries ?? 2;
|
|
906
|
-
|
|
907
|
-
// Bind the internal request method for the cloud sub-client
|
|
908
|
-
this.cloud = new EPCloudClient(this.request.bind(this));
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
private async request<T>(
|
|
912
|
-
method: string,
|
|
913
|
-
path: string,
|
|
914
|
-
body?: unknown,
|
|
915
|
-
auth = false,
|
|
916
|
-
): Promise<T> {
|
|
917
|
-
const url = `${this.baseUrl}${path}`;
|
|
918
|
-
const headers: Record<string, string> = {
|
|
919
|
-
'Content-Type': 'application/json',
|
|
920
|
-
'User-Agent': '@emilia-protocol/sdk/0.10.0',
|
|
921
|
-
};
|
|
922
|
-
if (auth && this.apiKey) {
|
|
923
|
-
headers['Authorization'] = `Bearer ${this.apiKey}`;
|
|
924
|
-
}
|
|
925
|
-
|
|
926
|
-
let lastErr: unknown;
|
|
927
|
-
for (let attempt = 0; attempt <= this.retries; attempt++) {
|
|
928
|
-
const ctrl = new AbortController();
|
|
929
|
-
const timer = setTimeout(() => ctrl.abort(), this.timeout);
|
|
930
|
-
try {
|
|
931
|
-
const res = await fetch(url, {
|
|
932
|
-
method,
|
|
933
|
-
headers,
|
|
934
|
-
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
935
|
-
signal: ctrl.signal,
|
|
936
|
-
});
|
|
937
|
-
const data: unknown = await res.json().catch(() => undefined);
|
|
938
|
-
if (!res.ok) {
|
|
939
|
-
const p = data as Record<string, unknown> | undefined;
|
|
940
|
-
const msg = typeof p?.['error'] === 'string'
|
|
941
|
-
? p['error']
|
|
942
|
-
: typeof p?.['detail'] === 'string'
|
|
943
|
-
? p['detail']
|
|
944
|
-
: typeof p?.['title'] === 'string'
|
|
945
|
-
? p['title']
|
|
946
|
-
: `EP API error: ${res.status}`;
|
|
947
|
-
const code = typeof p?.['code'] === 'string'
|
|
948
|
-
? p['code']
|
|
949
|
-
: typeof p?.['type'] === 'string'
|
|
950
|
-
? p['type'].split('/').pop()
|
|
951
|
-
: undefined;
|
|
952
|
-
throw new EPError(msg, res.status, code);
|
|
953
|
-
}
|
|
954
|
-
return data as T;
|
|
955
|
-
} catch (err) {
|
|
956
|
-
lastErr = err;
|
|
957
|
-
if (err instanceof EPError) {
|
|
958
|
-
// Only retry on 5xx
|
|
959
|
-
if (err.status && err.status < 500) throw err;
|
|
960
|
-
}
|
|
961
|
-
if (err instanceof Error && err.name === 'AbortError') {
|
|
962
|
-
lastErr = new EPError(`Request timed out after ${this.timeout}ms`, undefined, 'timeout');
|
|
963
|
-
}
|
|
964
|
-
if (attempt === this.retries) break;
|
|
965
|
-
} finally {
|
|
966
|
-
clearTimeout(timer);
|
|
967
|
-
}
|
|
968
|
-
}
|
|
969
|
-
if (lastErr instanceof EPError) throw lastErr;
|
|
970
|
-
throw new EPError(
|
|
971
|
-
lastErr instanceof Error ? lastErr.message : 'Unknown network error',
|
|
972
|
-
undefined,
|
|
973
|
-
'network_error',
|
|
974
|
-
);
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
// ------------------------------------------------------------------
|
|
978
|
-
// Core protocol endpoints
|
|
979
|
-
// ------------------------------------------------------------------
|
|
980
|
-
|
|
981
|
-
/** List available trust policies. */
|
|
982
|
-
async listPolicies(params?: { scope?: string }): Promise<Policy[]> {
|
|
983
|
-
const qs = params?.scope ? `?scope=${encodeURIComponent(params.scope)}` : '';
|
|
984
|
-
return this.request<Policy[]>('GET', `/api/policies${qs}`);
|
|
985
|
-
}
|
|
986
|
-
|
|
987
|
-
/** Initiate a trust handshake between parties. */
|
|
988
|
-
async initiateHandshake(params: InitiateHandshakeParams): Promise<Handshake> {
|
|
989
|
-
return this.request<Handshake>('POST', '/api/handshake/initiate', params, true);
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
/** Present credentials to a handshake. */
|
|
993
|
-
async present(handshakeId: string, params: PresentParams): Promise<Presentation> {
|
|
994
|
-
return this.request<Presentation>(
|
|
995
|
-
'POST',
|
|
996
|
-
`/api/handshake/${encodeURIComponent(handshakeId)}/present`,
|
|
997
|
-
params,
|
|
998
|
-
true,
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
/** Verify a handshake -- evaluate all presentations against policy. */
|
|
1003
|
-
async verify(handshakeId: string): Promise<VerificationResult> {
|
|
1004
|
-
return this.request<VerificationResult>(
|
|
1005
|
-
'POST',
|
|
1006
|
-
`/api/handshake/${encodeURIComponent(handshakeId)}/verify`,
|
|
1007
|
-
undefined,
|
|
1008
|
-
true,
|
|
1009
|
-
);
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
/** Pre-action trust gate. Returns allow/deny/review with commit ref. */
|
|
1013
|
-
async gate(params: GateParams): Promise<GateResult> {
|
|
1014
|
-
return this.request<GateResult>('POST', '/api/gate', {
|
|
1015
|
-
entity_id: params.entityId,
|
|
1016
|
-
action: params.action,
|
|
1017
|
-
policy: params.policy ?? 'standard',
|
|
1018
|
-
handshake_id: params.handshakeId,
|
|
1019
|
-
value_usd: params.valueUsd,
|
|
1020
|
-
delegation_id: params.delegationId,
|
|
1021
|
-
}, true);
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
/** Retrieve details of a specific handshake by ID. */
|
|
1025
|
-
async getHandshake(handshakeId: string): Promise<Handshake> {
|
|
1026
|
-
return this.request<Handshake>(
|
|
1027
|
-
'GET',
|
|
1028
|
-
`/api/handshake/${encodeURIComponent(handshakeId)}`,
|
|
1029
|
-
undefined,
|
|
1030
|
-
true,
|
|
1031
|
-
);
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
/** Revoke an active handshake, invalidating all associated state. */
|
|
1035
|
-
async revokeHandshake(handshakeId: string): Promise<RevokeResult> {
|
|
1036
|
-
return this.request<RevokeResult>(
|
|
1037
|
-
'POST',
|
|
1038
|
-
`/api/handshake/${encodeURIComponent(handshakeId)}/revoke`,
|
|
1039
|
-
undefined,
|
|
1040
|
-
true,
|
|
1041
|
-
);
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
/** Consume a handshake -- finalize and optionally bind a receipt. */
|
|
1045
|
-
async consume(handshakeId: string, params?: ConsumeParams): Promise<Consumption> {
|
|
1046
|
-
return this.request<Consumption>(
|
|
1047
|
-
'POST',
|
|
1048
|
-
`/api/handshake/${encodeURIComponent(handshakeId)}/consume`,
|
|
1049
|
-
params,
|
|
1050
|
-
true,
|
|
1051
|
-
);
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
// ------------------------------------------------------------------
|
|
1055
|
-
// v1 Trust Receipt Enforcement
|
|
1056
|
-
// ------------------------------------------------------------------
|
|
1057
|
-
|
|
1058
|
-
/** Create a v1 pre-action trust receipt for a high-risk mutation. */
|
|
1059
|
-
async createTrustReceipt(params: CreateTrustReceiptParams): Promise<TrustReceipt> {
|
|
1060
|
-
return this.request<TrustReceipt>('POST', '/api/v1/trust-receipts', trustReceiptBody(params), true);
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
/** Read current receipt state from the append-only v1 audit timeline. */
|
|
1064
|
-
async getTrustReceipt(receiptId: string): Promise<TrustReceiptState> {
|
|
1065
|
-
return this.request<TrustReceiptState>(
|
|
1066
|
-
'GET',
|
|
1067
|
-
`/api/v1/trust-receipts/${encodeURIComponent(receiptId)}`,
|
|
1068
|
-
undefined,
|
|
1069
|
-
true,
|
|
1070
|
-
);
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
/** Request human signoff for a receipt that requires approval. */
|
|
1074
|
-
async requestSignoff(params: RequestSignoffParams): Promise<SignoffRequest> {
|
|
1075
|
-
return this.request<SignoffRequest>('POST', '/api/v1/signoffs/request', {
|
|
1076
|
-
receipt_id: params.receiptId,
|
|
1077
|
-
approver_id: params.approverId,
|
|
1078
|
-
expires_in_minutes: params.expiresInMinutes,
|
|
1079
|
-
comment: params.comment,
|
|
1080
|
-
}, true);
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
/** Consume a receipt before mutation. If this fails, do not execute the write. */
|
|
1084
|
-
async consumeTrustReceipt(
|
|
1085
|
-
receiptId: string,
|
|
1086
|
-
params: { actionHash: string; executingSystem: string; executionReferenceId?: string },
|
|
1087
|
-
): Promise<ConsumeTrustReceiptResult> {
|
|
1088
|
-
return this.request<ConsumeTrustReceiptResult>(
|
|
1089
|
-
'POST',
|
|
1090
|
-
`/api/v1/trust-receipts/${encodeURIComponent(receiptId)}/consume`,
|
|
1091
|
-
{
|
|
1092
|
-
action_hash: params.actionHash,
|
|
1093
|
-
executing_system: params.executingSystem,
|
|
1094
|
-
execution_reference_id: params.executionReferenceId,
|
|
1095
|
-
},
|
|
1096
|
-
true,
|
|
1097
|
-
);
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
/** Emit the post-mutation execution attestation bound to the consumed receipt. */
|
|
1101
|
-
async attestExecution(
|
|
1102
|
-
receiptId: string,
|
|
1103
|
-
params: {
|
|
1104
|
-
executedAction: Record<string, unknown>;
|
|
1105
|
-
executingSystem: string;
|
|
1106
|
-
executionId?: string;
|
|
1107
|
-
executedAt?: string;
|
|
1108
|
-
},
|
|
1109
|
-
): Promise<ExecutionAttestation> {
|
|
1110
|
-
return this.request<ExecutionAttestation>(
|
|
1111
|
-
'POST',
|
|
1112
|
-
`/api/v1/trust-receipts/${encodeURIComponent(receiptId)}/execution`,
|
|
1113
|
-
{
|
|
1114
|
-
executed_action: params.executedAction,
|
|
1115
|
-
executing_system: params.executingSystem,
|
|
1116
|
-
execution_id: params.executionId,
|
|
1117
|
-
executed_at: params.executedAt,
|
|
1118
|
-
},
|
|
1119
|
-
true,
|
|
1120
|
-
);
|
|
1121
|
-
}
|
|
1122
|
-
|
|
1123
|
-
/** Fetch the signed evidence packet, when the receipt is in a signable state. */
|
|
1124
|
-
async getTrustReceiptEvidence(receiptId: string): Promise<TrustReceiptEvidence> {
|
|
1125
|
-
return this.request<TrustReceiptEvidence>(
|
|
1126
|
-
'GET',
|
|
1127
|
-
`/api/v1/trust-receipts/${encodeURIComponent(receiptId)}/evidence`,
|
|
1128
|
-
undefined,
|
|
1129
|
-
true,
|
|
1130
|
-
);
|
|
1131
|
-
}
|
|
1132
|
-
|
|
1133
|
-
/**
|
|
1134
|
-
* Wrap a dangerous mutation in the v1 receipt lifecycle.
|
|
1135
|
-
* The mutation runs only after create + consume succeed.
|
|
1136
|
-
*/
|
|
1137
|
-
async requireReceipt<T>(
|
|
1138
|
-
params: RequireReceiptParams,
|
|
1139
|
-
mutate: (ctx: { receipt: TrustReceipt; consume: ConsumeTrustReceiptResult }) => Promise<T>,
|
|
1140
|
-
): Promise<RequireReceiptResult<T>> {
|
|
1141
|
-
const receipt = await this.createTrustReceipt(params);
|
|
1142
|
-
if (receipt.decision === 'deny' || receipt.receipt_status === 'denied') {
|
|
1143
|
-
throw new EPError('EMILIA denied the action before execution', 403, 'receipt_denied');
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
|
-
let signoff: SignoffRequest | undefined;
|
|
1147
|
-
if (receipt.signoff_required) {
|
|
1148
|
-
if (!params.approverId && !params.quorumPolicy) {
|
|
1149
|
-
throw new EPError('Receipt requires signoff; pass approverId or quorumPolicy', 409, 'missing_approver_id');
|
|
1150
|
-
}
|
|
1151
|
-
signoff = await this.requestSignoff({
|
|
1152
|
-
receiptId: receipt.receipt_id,
|
|
1153
|
-
approverId: params.approverId,
|
|
1154
|
-
expiresInMinutes: params.signoffExpiresInMinutes,
|
|
1155
|
-
comment: params.signoffComment,
|
|
1156
|
-
});
|
|
1157
|
-
if (!params.onSignoffRequired) {
|
|
1158
|
-
throw new EPError('Receipt requires human signoff before the mutation can run', 409, 'signoff_required');
|
|
1159
|
-
}
|
|
1160
|
-
const signoffResult = await params.onSignoffRequired({ client: this, receipt, signoff });
|
|
1161
|
-
if (signoffResult === false || (typeof signoffResult === 'object' && signoffResult?.approved === false)) {
|
|
1162
|
-
throw new EPError('Human signoff was not approved', 403, 'signoff_rejected');
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
|
|
1166
|
-
const consume = await this.consumeTrustReceipt(receipt.receipt_id, {
|
|
1167
|
-
actionHash: receipt.action_hash,
|
|
1168
|
-
executingSystem: params.executingSystem,
|
|
1169
|
-
executionReferenceId: params.executionReferenceId,
|
|
1170
|
-
});
|
|
1171
|
-
const result = await mutate({ receipt, consume });
|
|
1172
|
-
const executedAction = typeof params.executedAction === 'function'
|
|
1173
|
-
? params.executedAction({ receipt, result })
|
|
1174
|
-
: params.executedAction ?? receipt.canonical_action;
|
|
1175
|
-
const executionId = typeof params.executionId === 'function'
|
|
1176
|
-
? params.executionId(result)
|
|
1177
|
-
: params.executionId;
|
|
1178
|
-
const execution = await this.attestExecution(receipt.receipt_id, {
|
|
1179
|
-
executedAction,
|
|
1180
|
-
executingSystem: params.executingSystem,
|
|
1181
|
-
executionId,
|
|
1182
|
-
});
|
|
1183
|
-
const evidence = params.fetchEvidence
|
|
1184
|
-
? await this.getTrustReceiptEvidence(receipt.receipt_id)
|
|
1185
|
-
: undefined;
|
|
1186
|
-
|
|
1187
|
-
return { result, receipt, signoff, consume, execution, evidence };
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
/** Wrap an existing async function with requireReceipt(). */
|
|
1191
|
-
withReceipt<TArgs extends unknown[], TResult>(
|
|
1192
|
-
params: RequireReceiptParams | ((...args: TArgs) => RequireReceiptParams),
|
|
1193
|
-
mutate: (...args: TArgs) => Promise<TResult>,
|
|
1194
|
-
): (...args: TArgs) => Promise<RequireReceiptResult<TResult>> {
|
|
1195
|
-
return async (...args: TArgs) => {
|
|
1196
|
-
const resolved = typeof params === 'function' ? params(...args) : params;
|
|
1197
|
-
return this.requireReceipt(resolved, () => mutate(...args));
|
|
1198
|
-
};
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
// ------------------------------------------------------------------
|
|
1202
|
-
// Signoff extension
|
|
1203
|
-
// ------------------------------------------------------------------
|
|
1204
|
-
|
|
1205
|
-
/** Issue a signoff challenge for an entity. */
|
|
1206
|
-
async issueChallenge(params: IssueChallengeParams): Promise<SignoffChallenge> {
|
|
1207
|
-
return this.request<SignoffChallenge>('POST', '/api/signoff/challenge', {
|
|
1208
|
-
entity_id: params.entityId,
|
|
1209
|
-
scope: params.scope,
|
|
1210
|
-
context: params.context,
|
|
1211
|
-
}, true);
|
|
1212
|
-
}
|
|
1213
|
-
|
|
1214
|
-
/** Attest to a signoff challenge with a cryptographic signature. */
|
|
1215
|
-
async attest(challengeId: string, params: AttestParams): Promise<SignoffAttestation> {
|
|
1216
|
-
return this.request<SignoffAttestation>(
|
|
1217
|
-
'POST',
|
|
1218
|
-
`/api/signoff/${encodeURIComponent(challengeId)}/attest`,
|
|
1219
|
-
params,
|
|
1220
|
-
true,
|
|
1221
|
-
);
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
/** Deny a signoff challenge with an optional reason. */
|
|
1225
|
-
async denyChallenge(challengeId: string, reason?: string): Promise<DenyResult> {
|
|
1226
|
-
return this.request<DenyResult>(
|
|
1227
|
-
'POST',
|
|
1228
|
-
`/api/signoff/${encodeURIComponent(challengeId)}/deny`,
|
|
1229
|
-
reason !== undefined ? { reason } : undefined,
|
|
1230
|
-
true,
|
|
1231
|
-
);
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
/** Revoke a previously granted signoff. */
|
|
1235
|
-
async revokeSignoff(challengeId: string, options?: RevokeSignoffOptions): Promise<RevokeResult> {
|
|
1236
|
-
return this.request<RevokeResult>(
|
|
1237
|
-
'POST',
|
|
1238
|
-
`/api/signoff/${encodeURIComponent(challengeId)}/revoke`,
|
|
1239
|
-
options,
|
|
1240
|
-
true,
|
|
1241
|
-
);
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
/** Consume a signoff -- mark it as used for a specific action. */
|
|
1245
|
-
async consumeSignoff(signoffId: string, params: ConsumeSignoffParams): Promise<SignoffConsumption> {
|
|
1246
|
-
return this.request<SignoffConsumption>(
|
|
1247
|
-
'POST',
|
|
1248
|
-
`/api/signoff/${encodeURIComponent(signoffId)}/consume`,
|
|
1249
|
-
params,
|
|
1250
|
-
true,
|
|
1251
|
-
);
|
|
1252
|
-
}
|
|
1253
|
-
|
|
1254
|
-
// ------------------------------------------------------------------
|
|
1255
|
-
// Delegation
|
|
1256
|
-
// ------------------------------------------------------------------
|
|
1257
|
-
|
|
1258
|
-
/** Create a trust delegation from one entity to another. */
|
|
1259
|
-
async createDelegation(params: CreateDelegationParams): Promise<Delegation> {
|
|
1260
|
-
return this.request<Delegation>('POST', '/api/delegation', {
|
|
1261
|
-
delegatorId: params.delegatorId,
|
|
1262
|
-
delegateeId: params.delegateeId,
|
|
1263
|
-
scope: params.scope,
|
|
1264
|
-
policyId: params.policyId,
|
|
1265
|
-
constraints: params.constraints,
|
|
1266
|
-
expiresAt: params.expiresAt,
|
|
1267
|
-
}, true);
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
/** Verify the validity of an existing delegation. */
|
|
1271
|
-
async verifyDelegation(delegationId: string): Promise<DelegationVerification> {
|
|
1272
|
-
return this.request<DelegationVerification>(
|
|
1273
|
-
'POST',
|
|
1274
|
-
`/api/delegation/${encodeURIComponent(delegationId)}/verify`,
|
|
1275
|
-
undefined,
|
|
1276
|
-
true,
|
|
1277
|
-
);
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
// ------------------------------------------------------------------
|
|
1281
|
-
// Commit
|
|
1282
|
-
// ------------------------------------------------------------------
|
|
1283
|
-
|
|
1284
|
-
/** Issue a trust commit binding a handshake to a specific action. */
|
|
1285
|
-
async issueCommit(params: IssueCommitParams): Promise<Commit> {
|
|
1286
|
-
return this.request<Commit>('POST', '/api/commit', {
|
|
1287
|
-
handshakeId: params.handshakeId,
|
|
1288
|
-
action: params.action,
|
|
1289
|
-
payload: params.payload,
|
|
1290
|
-
binding: params.binding,
|
|
1291
|
-
}, true);
|
|
1292
|
-
}
|
|
1293
|
-
|
|
1294
|
-
/** Verify a previously issued commit. */
|
|
1295
|
-
async verifyCommit(commitId: string): Promise<CommitVerification> {
|
|
1296
|
-
return this.request<CommitVerification>(
|
|
1297
|
-
'POST',
|
|
1298
|
-
`/api/commit/${encodeURIComponent(commitId)}/verify`,
|
|
1299
|
-
undefined,
|
|
1300
|
-
true,
|
|
1301
|
-
);
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
// ------------------------------------------------------------------
|
|
1305
|
-
// Eye — Observation & Advisory
|
|
1306
|
-
// ------------------------------------------------------------------
|
|
1307
|
-
|
|
1308
|
-
/** Record a behavioral or contextual observation for the Eye subsystem. */
|
|
1309
|
-
async recordObservation(params: RecordObservationParams): Promise<ObservationResponse> {
|
|
1310
|
-
return this.request<ObservationResponse>('POST', '/api/eye/observations', params, true);
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
/** Check an action against recorded observations and return an advisory. */
|
|
1314
|
-
async checkAction(params: CheckActionParams): Promise<AdvisoryResponse> {
|
|
1315
|
-
return this.request<AdvisoryResponse>('POST', '/api/eye/check', params, true);
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
/** Retrieve an existing advisory by ID. */
|
|
1319
|
-
async getAdvisory(advisoryId: string): Promise<AdvisoryResponse> {
|
|
1320
|
-
return this.request<AdvisoryResponse>(
|
|
1321
|
-
'GET',
|
|
1322
|
-
`/api/eye/advisories/${encodeURIComponent(advisoryId)}`,
|
|
1323
|
-
undefined,
|
|
1324
|
-
true,
|
|
1325
|
-
);
|
|
1326
|
-
}
|
|
1327
11
|
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
return this.request<SuppressionResponse>('POST', '/api/eye/suppressions', params, true);
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
12
|
+
export { EPClient } from './client.js';
|
|
13
|
+
export * from './types.js';
|