@atcn/sdk 1.3.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/LICENSE +202 -0
- package/README.md +25 -0
- package/bin/atcn.js +2 -0
- package/dist/builders.d.ts +44 -0
- package/dist/builders.js +61 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +2 -0
- package/dist/client.d.ts +395 -0
- package/dist/client.js +167 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +7 -0
- package/dist/init.d.ts +14 -0
- package/dist/init.js +45 -0
- package/dist/signer.d.ts +16 -0
- package/dist/signer.js +28 -0
- package/dist/subledger.d.ts +670 -0
- package/dist/subledger.js +300 -0
- package/package.json +45 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
import type { ClearingDecision, EventPayload, PublicKeyRecord, Signed } from "@atcn/schema";
|
|
2
|
+
export declare class AtcnApiError extends Error {
|
|
3
|
+
readonly status: number;
|
|
4
|
+
readonly code: string;
|
|
5
|
+
readonly reason: string | undefined;
|
|
6
|
+
readonly retryable: boolean;
|
|
7
|
+
readonly correlationId: string | undefined;
|
|
8
|
+
readonly details: unknown;
|
|
9
|
+
constructor(status: number, code: string, message: string, reason: string | undefined, retryable: boolean, correlationId: string | undefined, details: unknown);
|
|
10
|
+
}
|
|
11
|
+
/** Must equal this package's version in package.json (checked by a test). */
|
|
12
|
+
export declare const SDK_VERSION = "1.3.0";
|
|
13
|
+
/** Names the SDK and its version on every request, so the API operator can count SDK versions in use. Nothing else is sent. */
|
|
14
|
+
export declare const SDK_HEADER = "atcn-sdk";
|
|
15
|
+
export interface ClientOptions {
|
|
16
|
+
baseUrl: string;
|
|
17
|
+
apiKey: string;
|
|
18
|
+
/** Retries for retryable failures (same Idempotency-Key, so retries never duplicate effects). */
|
|
19
|
+
retries?: number;
|
|
20
|
+
fetch?: typeof fetch;
|
|
21
|
+
/** Extra headers sent on every request, for example `{ "atcn-workflow": "demo" }` from the bundled examples. */
|
|
22
|
+
headers?: Record<string, string>;
|
|
23
|
+
}
|
|
24
|
+
export interface RequestOptions {
|
|
25
|
+
idempotencyKey?: string;
|
|
26
|
+
query?: Record<string, string | number | undefined>;
|
|
27
|
+
headers?: Record<string, string>;
|
|
28
|
+
rawBody?: Uint8Array;
|
|
29
|
+
textBody?: {
|
|
30
|
+
contentType: string;
|
|
31
|
+
text: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
type SignedEvent = Signed<EventPayload>;
|
|
35
|
+
type Json = Record<string, unknown>;
|
|
36
|
+
/** Thin HTTP client for the ATCN API. Every mutating call carries an Idempotency-Key. */
|
|
37
|
+
export declare class AtcnClient {
|
|
38
|
+
private readonly options;
|
|
39
|
+
private readonly fetchImpl;
|
|
40
|
+
constructor(options: ClientOptions);
|
|
41
|
+
request<T = Json>(method: string, path: string, body?: unknown, opts?: RequestOptions): Promise<T>;
|
|
42
|
+
/**
|
|
43
|
+
* Creates or offers an obligation. With `subledger`, the obligation also becomes a delegation of one of the
|
|
44
|
+
* caller's subledger tasks; the link is not part of the signed event and is never shared with the counterparty.
|
|
45
|
+
*/
|
|
46
|
+
createObligation(signed: SignedEvent, subledger?: {
|
|
47
|
+
task_id: string;
|
|
48
|
+
parent_delegation_id?: string | null;
|
|
49
|
+
}): Promise<{
|
|
50
|
+
obligation: Json;
|
|
51
|
+
event: Json;
|
|
52
|
+
subledger?: {
|
|
53
|
+
task_id: string;
|
|
54
|
+
delegation_id: string;
|
|
55
|
+
};
|
|
56
|
+
}>;
|
|
57
|
+
acceptObligation(obligationId: string, signed: SignedEvent): Promise<{
|
|
58
|
+
obligation: Json;
|
|
59
|
+
event: Json;
|
|
60
|
+
}>;
|
|
61
|
+
appendEvent(obligationId: string, signed: SignedEvent): Promise<{
|
|
62
|
+
obligation: Json;
|
|
63
|
+
event: Json;
|
|
64
|
+
}>;
|
|
65
|
+
getObligation(obligationId: string): Promise<Json>;
|
|
66
|
+
listObligations(query?: {
|
|
67
|
+
state?: string;
|
|
68
|
+
root_id?: string;
|
|
69
|
+
limit?: number;
|
|
70
|
+
}): Promise<{
|
|
71
|
+
items: Json[];
|
|
72
|
+
}>;
|
|
73
|
+
listEvents(obligationId: string): Promise<{
|
|
74
|
+
items: Json[];
|
|
75
|
+
}>;
|
|
76
|
+
getChain(obligationId: string): Promise<Json>;
|
|
77
|
+
getAllocation(obligationId: string): Promise<Json>;
|
|
78
|
+
uploadBlob(bytes: Uint8Array, mediaType?: string): Promise<{
|
|
79
|
+
digest: string;
|
|
80
|
+
uri: string;
|
|
81
|
+
size_bytes: number;
|
|
82
|
+
}>;
|
|
83
|
+
submitEvidence(obligationId: string, signed: SignedEvent): Promise<{
|
|
84
|
+
evidence: Json;
|
|
85
|
+
event: Json;
|
|
86
|
+
reevaluation: {
|
|
87
|
+
decision: ClearingDecision;
|
|
88
|
+
reused: boolean;
|
|
89
|
+
} | null;
|
|
90
|
+
}>;
|
|
91
|
+
listEvidence(obligationId: string): Promise<{
|
|
92
|
+
items: Json[];
|
|
93
|
+
}>;
|
|
94
|
+
evidenceLink(evidenceId: string): Promise<{
|
|
95
|
+
url: string;
|
|
96
|
+
expires_at: string;
|
|
97
|
+
}>;
|
|
98
|
+
evaluate(obligationId: string, policy: {
|
|
99
|
+
policy_id: string;
|
|
100
|
+
policy_version: string;
|
|
101
|
+
}, idempotencyKey?: string): Promise<{
|
|
102
|
+
decision: ClearingDecision;
|
|
103
|
+
reused: boolean;
|
|
104
|
+
}>;
|
|
105
|
+
listDecisions(obligationId: string): Promise<{
|
|
106
|
+
items: ClearingDecision[];
|
|
107
|
+
}>;
|
|
108
|
+
finalize(decisionId: string, idempotencyKey?: string): Promise<Json>;
|
|
109
|
+
openDispute(decisionId: string, signed: SignedEvent): Promise<Json>;
|
|
110
|
+
reviewDispute(disputeId: string, signed: SignedEvent): Promise<Json>;
|
|
111
|
+
listDisputes(query?: {
|
|
112
|
+
status?: string;
|
|
113
|
+
obligation_id?: string;
|
|
114
|
+
}): Promise<{
|
|
115
|
+
items: Json[];
|
|
116
|
+
}>;
|
|
117
|
+
journal(query?: Record<string, string | number | undefined>): Promise<{
|
|
118
|
+
items: Json[];
|
|
119
|
+
}>;
|
|
120
|
+
statement(query?: Record<string, string | number | undefined>): Promise<Json>;
|
|
121
|
+
createSettlementInstruction(input: {
|
|
122
|
+
obligation_id: string;
|
|
123
|
+
beneficiary_ref: string;
|
|
124
|
+
amount_minor: number;
|
|
125
|
+
currency: string;
|
|
126
|
+
adapter: "manual" | "sandbox" | "stripe";
|
|
127
|
+
}, idempotencyKey?: string): Promise<Json>;
|
|
128
|
+
reportSettlementEvent(input: Json, idempotencyKey?: string): Promise<Json>;
|
|
129
|
+
reconciliationExceptions(status?: string): Promise<{
|
|
130
|
+
items: Json[];
|
|
131
|
+
}>;
|
|
132
|
+
exportClosurePackage(obligationId: string): Promise<{
|
|
133
|
+
payload: {
|
|
134
|
+
package_version: "1.0";
|
|
135
|
+
generated_at: string;
|
|
136
|
+
root_obligation_id: string;
|
|
137
|
+
requested_obligation_id: string;
|
|
138
|
+
obligations: {
|
|
139
|
+
obligation_id: string;
|
|
140
|
+
parent_obligation_id: string | null;
|
|
141
|
+
redacted: boolean;
|
|
142
|
+
effective_terms: {
|
|
143
|
+
schema_version: "1.0";
|
|
144
|
+
obligation_id: string;
|
|
145
|
+
terms_version: number;
|
|
146
|
+
parent_obligation_id: string | null;
|
|
147
|
+
principal_id: string;
|
|
148
|
+
payer_id: string;
|
|
149
|
+
issuer_agent_id: string;
|
|
150
|
+
counterparty_agent_id: string | null;
|
|
151
|
+
payee_selection: {
|
|
152
|
+
type: "open_offer";
|
|
153
|
+
allowed_platform_ids: string[];
|
|
154
|
+
} | null;
|
|
155
|
+
scope: {
|
|
156
|
+
task_type: string;
|
|
157
|
+
description: string;
|
|
158
|
+
artifact_ref?: string | undefined;
|
|
159
|
+
};
|
|
160
|
+
currency: string;
|
|
161
|
+
max_amount_minor: number;
|
|
162
|
+
deliverables: {
|
|
163
|
+
deliverable_id: string;
|
|
164
|
+
description: string;
|
|
165
|
+
amount_minor: number;
|
|
166
|
+
required_checks: string[];
|
|
167
|
+
}[];
|
|
168
|
+
acceptance_policy: {
|
|
169
|
+
policy_id: string;
|
|
170
|
+
policy_version: string;
|
|
171
|
+
policy_digest: string;
|
|
172
|
+
};
|
|
173
|
+
deadline: string;
|
|
174
|
+
offer_expires_at: string;
|
|
175
|
+
allow_subdelegation: boolean;
|
|
176
|
+
subdelegation_limits: {
|
|
177
|
+
max_depth: number;
|
|
178
|
+
max_total_minor: number;
|
|
179
|
+
allowed_policy_ids: string[];
|
|
180
|
+
} | null;
|
|
181
|
+
dispute_reviewer_id: string | null;
|
|
182
|
+
verifier_agent_ids: string[];
|
|
183
|
+
issued_at: string;
|
|
184
|
+
} | null;
|
|
185
|
+
effective_terms_digest: string | null;
|
|
186
|
+
state: string;
|
|
187
|
+
}[];
|
|
188
|
+
events: {
|
|
189
|
+
payload: {
|
|
190
|
+
schema_version: "1.0";
|
|
191
|
+
event_id: string;
|
|
192
|
+
event_type: string;
|
|
193
|
+
obligation_id: string;
|
|
194
|
+
actor_id: string;
|
|
195
|
+
actor_platform_id: string;
|
|
196
|
+
event_time: string;
|
|
197
|
+
causation_ids: string[];
|
|
198
|
+
data: Record<string, unknown>;
|
|
199
|
+
};
|
|
200
|
+
signature: {
|
|
201
|
+
key_id: string;
|
|
202
|
+
key_version: number;
|
|
203
|
+
algorithm: "Ed25519";
|
|
204
|
+
value: string;
|
|
205
|
+
};
|
|
206
|
+
payload_hash: string;
|
|
207
|
+
received_at: string;
|
|
208
|
+
sequence: number;
|
|
209
|
+
}[];
|
|
210
|
+
public_keys: {
|
|
211
|
+
key_id: string;
|
|
212
|
+
key_version: number;
|
|
213
|
+
actor_id: string;
|
|
214
|
+
algorithm: "Ed25519";
|
|
215
|
+
public_key: string;
|
|
216
|
+
valid_from: string;
|
|
217
|
+
revoked_at: string | null;
|
|
218
|
+
}[];
|
|
219
|
+
policies: {
|
|
220
|
+
schema_version: "1.0";
|
|
221
|
+
policy_id: string;
|
|
222
|
+
policy_version: string;
|
|
223
|
+
task_type: string;
|
|
224
|
+
description: string;
|
|
225
|
+
evidence_admissibility: {
|
|
226
|
+
allowed_producers: ("issuer" | "counterparty" | "verifier")[];
|
|
227
|
+
require_digest_match: boolean;
|
|
228
|
+
};
|
|
229
|
+
required_evidence: string[];
|
|
230
|
+
checks: {
|
|
231
|
+
check_id: string;
|
|
232
|
+
verifier: string;
|
|
233
|
+
verifier_version: string;
|
|
234
|
+
evidence_type: string;
|
|
235
|
+
config: Record<string, unknown>;
|
|
236
|
+
}[];
|
|
237
|
+
thresholds: {
|
|
238
|
+
partial_acceptance: boolean;
|
|
239
|
+
failed_portion_outcome: "disputed" | "rejected";
|
|
240
|
+
};
|
|
241
|
+
verifier_unavailable_outcome: "insufficient_evidence" | "disputed";
|
|
242
|
+
probabilistic_routing: "evidence_only" | "human_review";
|
|
243
|
+
timeouts: {
|
|
244
|
+
evaluation_window_seconds: number;
|
|
245
|
+
};
|
|
246
|
+
dispute: {
|
|
247
|
+
window_seconds: number;
|
|
248
|
+
review_window_seconds: number;
|
|
249
|
+
default_outcome: "uphold";
|
|
250
|
+
};
|
|
251
|
+
allocation: {
|
|
252
|
+
platform_fee_bps: number;
|
|
253
|
+
};
|
|
254
|
+
rounding: "largest_remainder";
|
|
255
|
+
}[];
|
|
256
|
+
evidence: {
|
|
257
|
+
evidence_id: string;
|
|
258
|
+
evidence_type: string;
|
|
259
|
+
producer_id: string;
|
|
260
|
+
created_at: string;
|
|
261
|
+
content_digest: string;
|
|
262
|
+
uri: string;
|
|
263
|
+
retrieval_method: "https" | "atcn-blob" | "out_of_band";
|
|
264
|
+
media_type: string;
|
|
265
|
+
access_policy: {
|
|
266
|
+
visible_to: ("issuer" | "counterparty" | "verifier" | "reviewer")[];
|
|
267
|
+
};
|
|
268
|
+
verifiers: string[];
|
|
269
|
+
deliverable_ids: string[];
|
|
270
|
+
}[];
|
|
271
|
+
verifier_results: {
|
|
272
|
+
result_id: string;
|
|
273
|
+
obligation_id: string;
|
|
274
|
+
check_id: string;
|
|
275
|
+
deliverable_id: string;
|
|
276
|
+
verifier_name: string;
|
|
277
|
+
verifier_version: string;
|
|
278
|
+
config_digest: string;
|
|
279
|
+
kind: "deterministic" | "probabilistic";
|
|
280
|
+
evidence_ids: string[];
|
|
281
|
+
evidence_digests: string[];
|
|
282
|
+
status: "pass" | "fail" | "invalid_evidence" | "missing_evidence" | "unavailable";
|
|
283
|
+
details: Record<string, unknown>;
|
|
284
|
+
model: {
|
|
285
|
+
name: string;
|
|
286
|
+
version: string;
|
|
287
|
+
confidence_bps: number;
|
|
288
|
+
} | null;
|
|
289
|
+
executed_at: string;
|
|
290
|
+
}[];
|
|
291
|
+
decisions: {
|
|
292
|
+
obligation_id: string;
|
|
293
|
+
terms_version: number;
|
|
294
|
+
terms_digest: string;
|
|
295
|
+
policy: {
|
|
296
|
+
policy_id: string;
|
|
297
|
+
policy_version: string;
|
|
298
|
+
policy_digest: string;
|
|
299
|
+
};
|
|
300
|
+
outcome: "insufficient_evidence" | "disputed" | "accepted" | "rejected" | "cancelled" | "expired" | "partially_accepted";
|
|
301
|
+
currency: string;
|
|
302
|
+
accepted_amount_minor: number;
|
|
303
|
+
rejected_amount_minor: number;
|
|
304
|
+
disputed_amount_minor: number;
|
|
305
|
+
pending_amount_minor: number;
|
|
306
|
+
deliverable_outcomes: {
|
|
307
|
+
deliverable_id: string;
|
|
308
|
+
amount_minor: number;
|
|
309
|
+
outcome: "insufficient_evidence" | "disputed" | "accepted" | "rejected";
|
|
310
|
+
reasons: {
|
|
311
|
+
code: "invalid_evidence" | "missing_evidence" | "failed_criteria" | "verifier_unavailable" | "probabilistic_review_required" | "partial_not_permitted" | "passed" | "dispute_amended" | "dispute_upheld";
|
|
312
|
+
check_id?: string | undefined;
|
|
313
|
+
evidence_type?: string | undefined;
|
|
314
|
+
detail?: string | undefined;
|
|
315
|
+
}[];
|
|
316
|
+
}[];
|
|
317
|
+
input_event_ids: string[];
|
|
318
|
+
evidence_digests: string[];
|
|
319
|
+
verifier_output_digests: string[];
|
|
320
|
+
decision_maker: {
|
|
321
|
+
type: "automated" | "human";
|
|
322
|
+
id: string;
|
|
323
|
+
};
|
|
324
|
+
decision_id: string;
|
|
325
|
+
decision_digest: string;
|
|
326
|
+
decided_at: string;
|
|
327
|
+
supersedes_decision_id: string | null;
|
|
328
|
+
input_cutoff_sequence: number;
|
|
329
|
+
}[];
|
|
330
|
+
posting_batches: {
|
|
331
|
+
batch_id: string;
|
|
332
|
+
obligation_id: string;
|
|
333
|
+
entry_type: "refund" | "reversal" | "contingent" | "dispute_freeze" | "settlement" | "reserve" | "clearing" | "dispute_release" | "return";
|
|
334
|
+
decision_id: string | null;
|
|
335
|
+
settlement_event_id: string | null;
|
|
336
|
+
reverses_batch_id: string | null;
|
|
337
|
+
policy_version: string | null;
|
|
338
|
+
source_event_ids: string[];
|
|
339
|
+
rounding: {
|
|
340
|
+
method: string;
|
|
341
|
+
detail: string;
|
|
342
|
+
} | null;
|
|
343
|
+
lines: {
|
|
344
|
+
account_type: "refund" | "payable" | "obligation_expense" | "contingent_expense" | "contingent_payable" | "receivable" | "platform_fee" | "dispute_frozen" | "reserve_reported" | "settlement_reported" | "unallocated_residual";
|
|
345
|
+
party_id: string;
|
|
346
|
+
allocation_role: "refund" | "contingent" | "dispute_freeze" | "settlement" | "reserve" | "platform_fee" | "unallocated_residual" | "payer_expense" | "payee_share" | "parent_margin" | "child_cost";
|
|
347
|
+
currency: string;
|
|
348
|
+
debit_minor: number;
|
|
349
|
+
credit_minor: number;
|
|
350
|
+
}[];
|
|
351
|
+
posted_at: string;
|
|
352
|
+
}[];
|
|
353
|
+
settlement_instructions: {
|
|
354
|
+
instruction_id: string;
|
|
355
|
+
obligation_id: string;
|
|
356
|
+
decision_id: string;
|
|
357
|
+
beneficiary_party_id: string;
|
|
358
|
+
beneficiary_ref: string;
|
|
359
|
+
currency: string;
|
|
360
|
+
amount_minor: number;
|
|
361
|
+
adapter: "manual" | "sandbox" | "stripe";
|
|
362
|
+
idempotency_key: string;
|
|
363
|
+
expires_at: string;
|
|
364
|
+
status: "unknown" | "failed" | "refunded" | "settled" | "returned" | "submitted" | "processing";
|
|
365
|
+
created_at: string;
|
|
366
|
+
}[];
|
|
367
|
+
settlement_events: {
|
|
368
|
+
settlement_event_id: string;
|
|
369
|
+
instruction_id: string | null;
|
|
370
|
+
provider: "manual" | "sandbox" | "stripe";
|
|
371
|
+
provider_event_id: string;
|
|
372
|
+
provider_reference: string;
|
|
373
|
+
provider_status: string;
|
|
374
|
+
normalized_status: "unknown" | "failed" | "refunded" | "settled" | "returned" | "submitted" | "processing";
|
|
375
|
+
currency: string;
|
|
376
|
+
amount_minor: number;
|
|
377
|
+
raw_json: string;
|
|
378
|
+
reported_at: string;
|
|
379
|
+
}[];
|
|
380
|
+
};
|
|
381
|
+
signature: {
|
|
382
|
+
key_id: string;
|
|
383
|
+
key_version: number;
|
|
384
|
+
algorithm: "Ed25519";
|
|
385
|
+
value: string;
|
|
386
|
+
};
|
|
387
|
+
}>;
|
|
388
|
+
serviceKeys(): Promise<{
|
|
389
|
+
items: PublicKeyRecord[];
|
|
390
|
+
}>;
|
|
391
|
+
keysForActor(actorId: string): Promise<{
|
|
392
|
+
items: PublicKeyRecord[];
|
|
393
|
+
}>;
|
|
394
|
+
}
|
|
395
|
+
export {};
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
export class AtcnApiError extends Error {
|
|
2
|
+
status;
|
|
3
|
+
code;
|
|
4
|
+
reason;
|
|
5
|
+
retryable;
|
|
6
|
+
correlationId;
|
|
7
|
+
details;
|
|
8
|
+
constructor(status, code, message, reason, retryable, correlationId, details) {
|
|
9
|
+
super(`${code}${reason ? ` (${reason})` : ""}: ${message}`);
|
|
10
|
+
this.status = status;
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.reason = reason;
|
|
13
|
+
this.retryable = retryable;
|
|
14
|
+
this.correlationId = correlationId;
|
|
15
|
+
this.details = details;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Must equal this package's version in package.json (checked by a test). */
|
|
19
|
+
export const SDK_VERSION = "1.3.0";
|
|
20
|
+
/** Names the SDK and its version on every request, so the API operator can count SDK versions in use. Nothing else is sent. */
|
|
21
|
+
export const SDK_HEADER = "atcn-sdk";
|
|
22
|
+
/** Thin HTTP client for the ATCN API. Every mutating call carries an Idempotency-Key. */
|
|
23
|
+
export class AtcnClient {
|
|
24
|
+
options;
|
|
25
|
+
fetchImpl;
|
|
26
|
+
constructor(options) {
|
|
27
|
+
this.options = options;
|
|
28
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
29
|
+
}
|
|
30
|
+
async request(method, path, body, opts = {}) {
|
|
31
|
+
const url = new URL(path, this.options.baseUrl);
|
|
32
|
+
for (const [k, v] of Object.entries(opts.query ?? {}))
|
|
33
|
+
if (v !== undefined)
|
|
34
|
+
url.searchParams.set(k, String(v));
|
|
35
|
+
const headers = {
|
|
36
|
+
[SDK_HEADER]: `typescript/${SDK_VERSION}`,
|
|
37
|
+
authorization: `Bearer ${this.options.apiKey}`,
|
|
38
|
+
...this.options.headers,
|
|
39
|
+
...opts.headers,
|
|
40
|
+
};
|
|
41
|
+
if (method !== "GET")
|
|
42
|
+
headers["idempotency-key"] = opts.idempotencyKey ?? crypto.randomUUID();
|
|
43
|
+
let payload;
|
|
44
|
+
if (opts.rawBody) {
|
|
45
|
+
headers["content-type"] = "application/octet-stream";
|
|
46
|
+
payload = opts.rawBody;
|
|
47
|
+
}
|
|
48
|
+
else if (opts.textBody) {
|
|
49
|
+
headers["content-type"] = opts.textBody.contentType;
|
|
50
|
+
payload = opts.textBody.text;
|
|
51
|
+
}
|
|
52
|
+
else if (body !== undefined) {
|
|
53
|
+
headers["content-type"] = "application/json";
|
|
54
|
+
payload = JSON.stringify(body);
|
|
55
|
+
}
|
|
56
|
+
const attempts = (this.options.retries ?? 2) + 1;
|
|
57
|
+
for (let attempt = 1;; attempt++) {
|
|
58
|
+
let response;
|
|
59
|
+
try {
|
|
60
|
+
response = await this.fetchImpl(url, { method, headers, body: payload });
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
if (attempt < attempts)
|
|
64
|
+
continue;
|
|
65
|
+
throw error;
|
|
66
|
+
}
|
|
67
|
+
const text = await response.text();
|
|
68
|
+
const parsed = text && response.headers.get("content-type")?.includes("json") ? JSON.parse(text) : text;
|
|
69
|
+
if (response.ok)
|
|
70
|
+
return parsed;
|
|
71
|
+
const err = parsed ?? {};
|
|
72
|
+
const apiError = new AtcnApiError(response.status, err.error?.code ?? "http_error", err.error?.message ?? String(parsed), err.error?.reason, err.error?.retryable ?? false, err.correlation_id, err.error?.details);
|
|
73
|
+
if (apiError.retryable && attempt < attempts) {
|
|
74
|
+
await new Promise((resolve) => setTimeout(resolve, 100 * 2 ** attempt));
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
throw apiError;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// ---- Obligations ----
|
|
81
|
+
/**
|
|
82
|
+
* Creates or offers an obligation. With `subledger`, the obligation also becomes a delegation of one of the
|
|
83
|
+
* caller's subledger tasks; the link is not part of the signed event and is never shared with the counterparty.
|
|
84
|
+
*/
|
|
85
|
+
createObligation(signed, subledger) {
|
|
86
|
+
return this.request("POST", "/v1/obligations", subledger ? { ...signed, subledger } : signed, { idempotencyKey: `event:${signed.payload.event_id}` });
|
|
87
|
+
}
|
|
88
|
+
acceptObligation(obligationId, signed) {
|
|
89
|
+
return this.request("POST", `/v1/obligations/${obligationId}/accept`, signed, { idempotencyKey: `event:${signed.payload.event_id}` });
|
|
90
|
+
}
|
|
91
|
+
appendEvent(obligationId, signed) {
|
|
92
|
+
return this.request("POST", `/v1/obligations/${obligationId}/events`, signed, { idempotencyKey: `event:${signed.payload.event_id}` });
|
|
93
|
+
}
|
|
94
|
+
getObligation(obligationId) {
|
|
95
|
+
return this.request("GET", `/v1/obligations/${obligationId}`);
|
|
96
|
+
}
|
|
97
|
+
listObligations(query = {}) {
|
|
98
|
+
return this.request("GET", "/v1/obligations", undefined, { query });
|
|
99
|
+
}
|
|
100
|
+
listEvents(obligationId) {
|
|
101
|
+
return this.request("GET", `/v1/obligations/${obligationId}/events`);
|
|
102
|
+
}
|
|
103
|
+
getChain(obligationId) {
|
|
104
|
+
return this.request("GET", `/v1/obligations/${obligationId}/chain`);
|
|
105
|
+
}
|
|
106
|
+
getAllocation(obligationId) {
|
|
107
|
+
return this.request("GET", `/v1/obligations/${obligationId}/allocation`);
|
|
108
|
+
}
|
|
109
|
+
// ---- Evidence ----
|
|
110
|
+
uploadBlob(bytes, mediaType = "application/octet-stream") {
|
|
111
|
+
return this.request("POST", "/v1/blobs", undefined, { rawBody: bytes, headers: { "x-media-type": mediaType } });
|
|
112
|
+
}
|
|
113
|
+
submitEvidence(obligationId, signed) {
|
|
114
|
+
return this.request("POST", `/v1/obligations/${obligationId}/evidence`, signed, { idempotencyKey: `event:${signed.payload.event_id}` });
|
|
115
|
+
}
|
|
116
|
+
listEvidence(obligationId) {
|
|
117
|
+
return this.request("GET", `/v1/obligations/${obligationId}/evidence`);
|
|
118
|
+
}
|
|
119
|
+
evidenceLink(evidenceId) {
|
|
120
|
+
return this.request("GET", `/v1/evidence/${evidenceId}/link`);
|
|
121
|
+
}
|
|
122
|
+
// ---- Clearing and disputes ----
|
|
123
|
+
evaluate(obligationId, policy, idempotencyKey) {
|
|
124
|
+
return this.request("POST", `/v1/obligations/${obligationId}/evaluate`, policy, { idempotencyKey });
|
|
125
|
+
}
|
|
126
|
+
listDecisions(obligationId) {
|
|
127
|
+
return this.request("GET", `/v1/obligations/${obligationId}/decisions`);
|
|
128
|
+
}
|
|
129
|
+
finalize(decisionId, idempotencyKey) {
|
|
130
|
+
return this.request("POST", `/v1/decisions/${decisionId}/finalize`, undefined, { idempotencyKey });
|
|
131
|
+
}
|
|
132
|
+
openDispute(decisionId, signed) {
|
|
133
|
+
return this.request("POST", `/v1/decisions/${decisionId}/disputes`, signed, { idempotencyKey: `event:${signed.payload.event_id}` });
|
|
134
|
+
}
|
|
135
|
+
reviewDispute(disputeId, signed) {
|
|
136
|
+
return this.request("POST", `/v1/disputes/${disputeId}/review`, signed, { idempotencyKey: `event:${signed.payload.event_id}` });
|
|
137
|
+
}
|
|
138
|
+
listDisputes(query = {}) {
|
|
139
|
+
return this.request("GET", "/v1/disputes", undefined, { query });
|
|
140
|
+
}
|
|
141
|
+
// ---- Journal, settlement, reconciliation, exports ----
|
|
142
|
+
journal(query = {}) {
|
|
143
|
+
return this.request("GET", "/v1/journal", undefined, { query });
|
|
144
|
+
}
|
|
145
|
+
statement(query = {}) {
|
|
146
|
+
return this.request("GET", "/v1/journal/statement", undefined, { query });
|
|
147
|
+
}
|
|
148
|
+
createSettlementInstruction(input, idempotencyKey) {
|
|
149
|
+
return this.request("POST", "/v1/settlements/instructions", input, { idempotencyKey });
|
|
150
|
+
}
|
|
151
|
+
reportSettlementEvent(input, idempotencyKey) {
|
|
152
|
+
return this.request("POST", "/v1/settlements/events", input, { idempotencyKey });
|
|
153
|
+
}
|
|
154
|
+
reconciliationExceptions(status) {
|
|
155
|
+
return this.request("GET", "/v1/reconciliation/exceptions", undefined, { query: { status } });
|
|
156
|
+
}
|
|
157
|
+
exportClosurePackage(obligationId) {
|
|
158
|
+
return this.request("GET", `/v1/exports/${obligationId}`);
|
|
159
|
+
}
|
|
160
|
+
// ---- Keys ----
|
|
161
|
+
serviceKeys() {
|
|
162
|
+
return this.request("GET", "/v1/service/keys");
|
|
163
|
+
}
|
|
164
|
+
keysForActor(actorId) {
|
|
165
|
+
return this.request("GET", "/v1/keys", undefined, { query: { actor_id: actorId } });
|
|
166
|
+
}
|
|
167
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { EventSigner, type SignerIdentity } from "./signer.js";
|
|
2
|
+
export { buildTerms, termsData, acceptanceData, buildEvidenceEnvelope, type TermsInput, type EnvelopeInput } from "./builders.js";
|
|
3
|
+
export { AtcnClient, AtcnApiError, SDK_HEADER, SDK_VERSION, type ClientOptions, type RequestOptions } from "./client.js";
|
|
4
|
+
export { verifyClosurePackage, REFERENCE_POLICIES, CODE_CHANGE_POLICY_V1, CODE_CHANGE_POLICY_V1_1, CODE_CHANGE_SUBTASK_POLICY_V1 } from "@atcn/core";
|
|
5
|
+
export { SubledgerClient, ReceiptLinkClient, CaptureQueue, ext, stableKey, type CaptureOperation, type CaptureQueueOptions, type FlushResult } from "./subledger.js";
|
|
6
|
+
export { verifySubledgerDocument, buildResponseStatement, signStatement, verifyStatementSignature } from "@atcn/subledger";
|
|
7
|
+
export { verifyWebhook, signWebhook, WEBHOOK_SIGNATURE_HEADER, generateKeyPair, digestOf, sha256Digest, canonicalize } from "@atcn/schema";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { EventSigner } from "./signer.js";
|
|
2
|
+
export { buildTerms, termsData, acceptanceData, buildEvidenceEnvelope } from "./builders.js";
|
|
3
|
+
export { AtcnClient, AtcnApiError, SDK_HEADER, SDK_VERSION } from "./client.js";
|
|
4
|
+
export { verifyClosurePackage, REFERENCE_POLICIES, CODE_CHANGE_POLICY_V1, CODE_CHANGE_POLICY_V1_1, CODE_CHANGE_SUBTASK_POLICY_V1 } from "@atcn/core";
|
|
5
|
+
export { SubledgerClient, ReceiptLinkClient, CaptureQueue, ext, stableKey } from "./subledger.js";
|
|
6
|
+
export { verifySubledgerDocument, buildResponseStatement, signStatement, verifyStatementSignature } from "@atcn/subledger";
|
|
7
|
+
export { verifyWebhook, signWebhook, WEBHOOK_SIGNATURE_HEADER, generateKeyPair, digestOf, sha256Digest, canonicalize } from "@atcn/schema";
|
package/dist/init.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type ConsentIo, type Env } from "@atcn/usage";
|
|
2
|
+
export interface CliOptions {
|
|
3
|
+
env?: Env;
|
|
4
|
+
io?: ConsentIo;
|
|
5
|
+
interactive?: boolean;
|
|
6
|
+
fetch?: typeof fetch;
|
|
7
|
+
log?: (line: string) => void;
|
|
8
|
+
error?: (line: string) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `atcn init` records whether this machine shares anonymous usage metrics, by flag or by asking. On a yes it
|
|
12
|
+
* reports `integration_initialized`. Returns the process exit code: 0 saved, 2 usage error or no answer.
|
|
13
|
+
*/
|
|
14
|
+
export declare function runCli(argv: string[], options?: CliOptions): Promise<number>;
|
package/dist/init.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
import { askToShareUsage, saveUsageChoice, sendUsageReport, settingsPath, usageStatus } from "@atcn/usage";
|
|
3
|
+
import { SDK_VERSION } from "./client.js";
|
|
4
|
+
const USAGE = "usage: atcn init [--share-usage yes|no]";
|
|
5
|
+
/**
|
|
6
|
+
* `atcn init` records whether this machine shares anonymous usage metrics, by flag or by asking. On a yes it
|
|
7
|
+
* reports `integration_initialized`. Returns the process exit code: 0 saved, 2 usage error or no answer.
|
|
8
|
+
*/
|
|
9
|
+
export async function runCli(argv, options = {}) {
|
|
10
|
+
const env = options.env ?? process.env;
|
|
11
|
+
const log = options.log ?? console.log;
|
|
12
|
+
const error = options.error ?? console.error;
|
|
13
|
+
let parsed;
|
|
14
|
+
try {
|
|
15
|
+
parsed = parseArgs({ args: argv, options: { "share-usage": { type: "string" } }, allowPositionals: true });
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
error(USAGE);
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
const flag = parsed.values["share-usage"];
|
|
22
|
+
if (parsed.positionals.length !== 1 || parsed.positionals[0] !== "init" || (flag !== undefined && flag !== "yes" && flag !== "no")) {
|
|
23
|
+
error(USAGE);
|
|
24
|
+
return 2;
|
|
25
|
+
}
|
|
26
|
+
let shared;
|
|
27
|
+
if (flag !== undefined)
|
|
28
|
+
shared = saveUsageChoice(flag === "yes", env).share_usage;
|
|
29
|
+
else if (options.interactive ?? process.stdin.isTTY === true)
|
|
30
|
+
shared = await askToShareUsage(options.io, env);
|
|
31
|
+
else {
|
|
32
|
+
error("Not an interactive terminal: pass --share-usage yes or --share-usage no.");
|
|
33
|
+
return 2;
|
|
34
|
+
}
|
|
35
|
+
if (shared === null) {
|
|
36
|
+
error("No answer given; nothing saved.");
|
|
37
|
+
return 2;
|
|
38
|
+
}
|
|
39
|
+
if (shared) {
|
|
40
|
+
await sendUsageReport({ event: "integration_initialized", sdk_version: `typescript/${SDK_VERSION}`, workflow: "custom", delegations: null, charges: null }, { env, fetch: options.fetch });
|
|
41
|
+
}
|
|
42
|
+
log(`Saved your choice to ${settingsPath(env)}.`);
|
|
43
|
+
log(`Usage metrics: ${usageStatus(env).reason}.`);
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
package/dist/signer.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type EventPayload, type EventType, type Signed } from "@atcn/schema";
|
|
2
|
+
export interface SignerIdentity {
|
|
3
|
+
actorId: string;
|
|
4
|
+
platformId: string;
|
|
5
|
+
keyId: string;
|
|
6
|
+
keyVersion?: number;
|
|
7
|
+
privateKey: string;
|
|
8
|
+
}
|
|
9
|
+
/** Signs ATCN events for one actor. Keys stay with the caller; ATCN only ever sees public keys. */
|
|
10
|
+
export declare class EventSigner {
|
|
11
|
+
readonly identity: SignerIdentity;
|
|
12
|
+
constructor(identity: SignerIdentity);
|
|
13
|
+
get actorId(): string;
|
|
14
|
+
get platformId(): string;
|
|
15
|
+
sign(eventType: EventType, obligationId: string, data?: Record<string, unknown>, causationIds?: string[]): Signed<EventPayload>;
|
|
16
|
+
}
|