@paysentry/protect 1.0.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/dist/disputes.d.ts +138 -0
- package/dist/disputes.d.ts.map +1 -0
- package/dist/disputes.js +282 -0
- package/dist/disputes.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/provenance.d.ts +80 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +180 -0
- package/dist/provenance.js.map +1 -0
- package/dist/recovery.d.ts +127 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +222 -0
- package/dist/recovery.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { DisputeCase, DisputeEvidence, DisputeId, DisputeStatus, TransactionId, AgentId, LiabilityAttribution, Logger } from '@paysentry/core';
|
|
2
|
+
import type { TransactionProvenance } from './provenance.js';
|
|
3
|
+
/** Options for filing a new dispute */
|
|
4
|
+
export interface FileDisputeInput {
|
|
5
|
+
/** Transaction being disputed */
|
|
6
|
+
readonly transactionId: TransactionId;
|
|
7
|
+
/** Agent filing the dispute */
|
|
8
|
+
readonly agentId: AgentId;
|
|
9
|
+
/** Reason for the dispute */
|
|
10
|
+
readonly reason: string;
|
|
11
|
+
/** Amount requested for refund */
|
|
12
|
+
readonly requestedAmount: number;
|
|
13
|
+
/** Initial evidence (optional) */
|
|
14
|
+
readonly evidence?: DisputeEvidence[];
|
|
15
|
+
}
|
|
16
|
+
/** Filter for querying disputes */
|
|
17
|
+
export interface DisputeFilter {
|
|
18
|
+
/** Filter by status */
|
|
19
|
+
readonly status?: DisputeStatus;
|
|
20
|
+
/** Filter by agent */
|
|
21
|
+
readonly agentId?: AgentId;
|
|
22
|
+
/** Filter by transaction */
|
|
23
|
+
readonly transactionId?: TransactionId;
|
|
24
|
+
/** Filter by liability */
|
|
25
|
+
readonly liability?: LiabilityAttribution;
|
|
26
|
+
/** Maximum results */
|
|
27
|
+
readonly limit?: number;
|
|
28
|
+
}
|
|
29
|
+
/** Callback for dispute status changes */
|
|
30
|
+
export type DisputeListener = (dispute: DisputeCase, previousStatus: DisputeStatus) => void | Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* DisputeManager handles the full lifecycle of payment disputes:
|
|
33
|
+
* filing, investigation, evidence collection, liability attribution,
|
|
34
|
+
* and resolution.
|
|
35
|
+
*
|
|
36
|
+
* It integrates with TransactionProvenance to automatically pull
|
|
37
|
+
* the transaction's audit trail as evidence.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```ts
|
|
41
|
+
* const disputes = new DisputeManager({ provenance });
|
|
42
|
+
*
|
|
43
|
+
* // File a dispute
|
|
44
|
+
* const dispute = disputes.file({
|
|
45
|
+
* transactionId: tx.id,
|
|
46
|
+
* agentId: tx.agentId,
|
|
47
|
+
* reason: 'Service not delivered after payment',
|
|
48
|
+
* requestedAmount: tx.amount,
|
|
49
|
+
* });
|
|
50
|
+
*
|
|
51
|
+
* // Add evidence
|
|
52
|
+
* disputes.addEvidence(dispute.id, {
|
|
53
|
+
* type: 'user_statement',
|
|
54
|
+
* description: 'Agent completed payment but received 404 from service',
|
|
55
|
+
* data: { httpStatus: 404, url: 'https://api.service.com/resource' },
|
|
56
|
+
* addedAt: new Date().toISOString(),
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* // Resolve
|
|
60
|
+
* disputes.resolve(dispute.id, {
|
|
61
|
+
* status: 'resolved_refunded',
|
|
62
|
+
* liability: 'service_provider',
|
|
63
|
+
* resolvedAmount: tx.amount,
|
|
64
|
+
* });
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare class DisputeManager {
|
|
68
|
+
/** All disputes, keyed by dispute ID */
|
|
69
|
+
private readonly disputes;
|
|
70
|
+
/** Index: transactionId -> disputeId */
|
|
71
|
+
private readonly byTransaction;
|
|
72
|
+
/** Index: agentId -> set of dispute IDs */
|
|
73
|
+
private readonly byAgent;
|
|
74
|
+
/** Status change listeners */
|
|
75
|
+
private readonly listeners;
|
|
76
|
+
private readonly provenance?;
|
|
77
|
+
private readonly logger?;
|
|
78
|
+
constructor(options?: {
|
|
79
|
+
provenance?: TransactionProvenance;
|
|
80
|
+
logger?: Logger;
|
|
81
|
+
});
|
|
82
|
+
/**
|
|
83
|
+
* File a new dispute case.
|
|
84
|
+
* Automatically pulls provenance records as initial evidence if available.
|
|
85
|
+
*/
|
|
86
|
+
file(input: FileDisputeInput): DisputeCase;
|
|
87
|
+
/**
|
|
88
|
+
* Add evidence to an existing dispute.
|
|
89
|
+
*/
|
|
90
|
+
addEvidence(disputeId: DisputeId, evidence: DisputeEvidence): void;
|
|
91
|
+
/**
|
|
92
|
+
* Update the status of a dispute (e.g., open -> investigating).
|
|
93
|
+
*/
|
|
94
|
+
updateStatus(disputeId: DisputeId, newStatus: DisputeStatus): void;
|
|
95
|
+
/**
|
|
96
|
+
* Resolve a dispute with a final determination.
|
|
97
|
+
*/
|
|
98
|
+
resolve(disputeId: DisputeId, resolution: {
|
|
99
|
+
status: 'resolved_refunded' | 'resolved_denied' | 'resolved_partial';
|
|
100
|
+
liability: LiabilityAttribution;
|
|
101
|
+
resolvedAmount?: number;
|
|
102
|
+
}): DisputeCase;
|
|
103
|
+
/**
|
|
104
|
+
* Get a dispute by ID.
|
|
105
|
+
*/
|
|
106
|
+
get(disputeId: DisputeId): DisputeCase | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* Get the dispute associated with a transaction.
|
|
109
|
+
*/
|
|
110
|
+
getByTransaction(txId: TransactionId): DisputeCase | undefined;
|
|
111
|
+
/**
|
|
112
|
+
* Get all disputes for an agent.
|
|
113
|
+
*/
|
|
114
|
+
getByAgent(agentId: AgentId): DisputeCase[];
|
|
115
|
+
/**
|
|
116
|
+
* Query disputes with filtering.
|
|
117
|
+
*/
|
|
118
|
+
query(filter: DisputeFilter): DisputeCase[];
|
|
119
|
+
/**
|
|
120
|
+
* Register a listener for dispute status changes.
|
|
121
|
+
*/
|
|
122
|
+
onStatusChange(listener: DisputeListener): void;
|
|
123
|
+
/**
|
|
124
|
+
* Get summary statistics for disputes.
|
|
125
|
+
*/
|
|
126
|
+
getStats(): {
|
|
127
|
+
total: number;
|
|
128
|
+
open: number;
|
|
129
|
+
investigating: number;
|
|
130
|
+
resolved: number;
|
|
131
|
+
escalated: number;
|
|
132
|
+
totalRequestedAmount: number;
|
|
133
|
+
totalResolvedAmount: number;
|
|
134
|
+
};
|
|
135
|
+
private isClosed;
|
|
136
|
+
private notifyListeners;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=disputes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disputes.d.ts","sourceRoot":"","sources":["../src/disputes.ts"],"names":[],"mappings":"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"}
|
package/dist/disputes.js
ADDED
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// DisputeManager — Open, track, and resolve payment disputes
|
|
3
|
+
// Central registry for all dispute cases with lifecycle management
|
|
4
|
+
// =============================================================================
|
|
5
|
+
import { generateDisputeId } from '@paysentry/core';
|
|
6
|
+
/**
|
|
7
|
+
* DisputeManager handles the full lifecycle of payment disputes:
|
|
8
|
+
* filing, investigation, evidence collection, liability attribution,
|
|
9
|
+
* and resolution.
|
|
10
|
+
*
|
|
11
|
+
* It integrates with TransactionProvenance to automatically pull
|
|
12
|
+
* the transaction's audit trail as evidence.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```ts
|
|
16
|
+
* const disputes = new DisputeManager({ provenance });
|
|
17
|
+
*
|
|
18
|
+
* // File a dispute
|
|
19
|
+
* const dispute = disputes.file({
|
|
20
|
+
* transactionId: tx.id,
|
|
21
|
+
* agentId: tx.agentId,
|
|
22
|
+
* reason: 'Service not delivered after payment',
|
|
23
|
+
* requestedAmount: tx.amount,
|
|
24
|
+
* });
|
|
25
|
+
*
|
|
26
|
+
* // Add evidence
|
|
27
|
+
* disputes.addEvidence(dispute.id, {
|
|
28
|
+
* type: 'user_statement',
|
|
29
|
+
* description: 'Agent completed payment but received 404 from service',
|
|
30
|
+
* data: { httpStatus: 404, url: 'https://api.service.com/resource' },
|
|
31
|
+
* addedAt: new Date().toISOString(),
|
|
32
|
+
* });
|
|
33
|
+
*
|
|
34
|
+
* // Resolve
|
|
35
|
+
* disputes.resolve(dispute.id, {
|
|
36
|
+
* status: 'resolved_refunded',
|
|
37
|
+
* liability: 'service_provider',
|
|
38
|
+
* resolvedAmount: tx.amount,
|
|
39
|
+
* });
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export class DisputeManager {
|
|
43
|
+
/** All disputes, keyed by dispute ID */
|
|
44
|
+
disputes = new Map();
|
|
45
|
+
/** Index: transactionId -> disputeId */
|
|
46
|
+
byTransaction = new Map();
|
|
47
|
+
/** Index: agentId -> set of dispute IDs */
|
|
48
|
+
byAgent = new Map();
|
|
49
|
+
/** Status change listeners */
|
|
50
|
+
listeners = [];
|
|
51
|
+
provenance;
|
|
52
|
+
logger;
|
|
53
|
+
constructor(options) {
|
|
54
|
+
this.provenance = options?.provenance;
|
|
55
|
+
this.logger = options?.logger;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* File a new dispute case.
|
|
59
|
+
* Automatically pulls provenance records as initial evidence if available.
|
|
60
|
+
*/
|
|
61
|
+
file(input) {
|
|
62
|
+
// Check if dispute already exists for this transaction
|
|
63
|
+
const existing = this.byTransaction.get(input.transactionId);
|
|
64
|
+
if (existing) {
|
|
65
|
+
const existingCase = this.disputes.get(existing);
|
|
66
|
+
if (existingCase && !this.isClosed(existingCase.status)) {
|
|
67
|
+
throw new Error(`Active dispute ${existing} already exists for transaction ${input.transactionId}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
const now = new Date().toISOString();
|
|
71
|
+
const evidence = [];
|
|
72
|
+
// Pull provenance records as evidence
|
|
73
|
+
if (this.provenance) {
|
|
74
|
+
const chain = this.provenance.getChain(input.transactionId);
|
|
75
|
+
if (chain.length > 0) {
|
|
76
|
+
evidence.push({
|
|
77
|
+
type: 'transaction_log',
|
|
78
|
+
description: `Transaction provenance chain (${chain.length} records)`,
|
|
79
|
+
data: chain,
|
|
80
|
+
addedAt: now,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Add user-provided evidence
|
|
85
|
+
if (input.evidence) {
|
|
86
|
+
evidence.push(...input.evidence);
|
|
87
|
+
}
|
|
88
|
+
const dispute = {
|
|
89
|
+
id: generateDisputeId(),
|
|
90
|
+
transactionId: input.transactionId,
|
|
91
|
+
agentId: input.agentId,
|
|
92
|
+
reason: input.reason,
|
|
93
|
+
status: 'open',
|
|
94
|
+
liability: 'undetermined',
|
|
95
|
+
requestedAmount: input.requestedAmount,
|
|
96
|
+
createdAt: now,
|
|
97
|
+
updatedAt: now,
|
|
98
|
+
evidence,
|
|
99
|
+
};
|
|
100
|
+
this.disputes.set(dispute.id, dispute);
|
|
101
|
+
this.byTransaction.set(input.transactionId, dispute.id);
|
|
102
|
+
let agentSet = this.byAgent.get(input.agentId);
|
|
103
|
+
if (!agentSet) {
|
|
104
|
+
agentSet = new Set();
|
|
105
|
+
this.byAgent.set(input.agentId, agentSet);
|
|
106
|
+
}
|
|
107
|
+
agentSet.add(dispute.id);
|
|
108
|
+
// Record in provenance
|
|
109
|
+
if (this.provenance) {
|
|
110
|
+
this.provenance.recordDispute(input.transactionId, {
|
|
111
|
+
disputeId: dispute.id,
|
|
112
|
+
reason: input.reason,
|
|
113
|
+
requestedAmount: input.requestedAmount,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
this.logger?.info(`[DisputeManager] Filed dispute ${dispute.id} for tx ${input.transactionId}`);
|
|
117
|
+
return dispute;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Add evidence to an existing dispute.
|
|
121
|
+
*/
|
|
122
|
+
addEvidence(disputeId, evidence) {
|
|
123
|
+
const dispute = this.disputes.get(disputeId);
|
|
124
|
+
if (!dispute) {
|
|
125
|
+
throw new Error(`Dispute ${disputeId} not found`);
|
|
126
|
+
}
|
|
127
|
+
if (this.isClosed(dispute.status)) {
|
|
128
|
+
throw new Error(`Cannot add evidence to closed dispute ${disputeId}`);
|
|
129
|
+
}
|
|
130
|
+
dispute.evidence.push(evidence);
|
|
131
|
+
dispute.updatedAt = new Date().toISOString();
|
|
132
|
+
this.logger?.info(`[DisputeManager] Added evidence to dispute ${disputeId}`, {
|
|
133
|
+
type: evidence.type,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Update the status of a dispute (e.g., open -> investigating).
|
|
138
|
+
*/
|
|
139
|
+
updateStatus(disputeId, newStatus) {
|
|
140
|
+
const dispute = this.disputes.get(disputeId);
|
|
141
|
+
if (!dispute) {
|
|
142
|
+
throw new Error(`Dispute ${disputeId} not found`);
|
|
143
|
+
}
|
|
144
|
+
const previousStatus = dispute.status;
|
|
145
|
+
dispute.status = newStatus;
|
|
146
|
+
dispute.updatedAt = new Date().toISOString();
|
|
147
|
+
this.logger?.info(`[DisputeManager] Dispute ${disputeId} status: ${previousStatus} -> ${newStatus}`);
|
|
148
|
+
// Notify listeners
|
|
149
|
+
this.notifyListeners(dispute, previousStatus);
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Resolve a dispute with a final determination.
|
|
153
|
+
*/
|
|
154
|
+
resolve(disputeId, resolution) {
|
|
155
|
+
const dispute = this.disputes.get(disputeId);
|
|
156
|
+
if (!dispute) {
|
|
157
|
+
throw new Error(`Dispute ${disputeId} not found`);
|
|
158
|
+
}
|
|
159
|
+
const previousStatus = dispute.status;
|
|
160
|
+
dispute.status = resolution.status;
|
|
161
|
+
dispute.liability = resolution.liability;
|
|
162
|
+
dispute.resolvedAmount = resolution.resolvedAmount;
|
|
163
|
+
dispute.resolvedAt = new Date().toISOString();
|
|
164
|
+
dispute.updatedAt = dispute.resolvedAt;
|
|
165
|
+
this.logger?.info(`[DisputeManager] Resolved dispute ${disputeId}: ${resolution.status}, liability=${resolution.liability}`);
|
|
166
|
+
this.notifyListeners(dispute, previousStatus);
|
|
167
|
+
return dispute;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get a dispute by ID.
|
|
171
|
+
*/
|
|
172
|
+
get(disputeId) {
|
|
173
|
+
return this.disputes.get(disputeId);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get the dispute associated with a transaction.
|
|
177
|
+
*/
|
|
178
|
+
getByTransaction(txId) {
|
|
179
|
+
const disputeId = this.byTransaction.get(txId);
|
|
180
|
+
return disputeId ? this.disputes.get(disputeId) : undefined;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Get all disputes for an agent.
|
|
184
|
+
*/
|
|
185
|
+
getByAgent(agentId) {
|
|
186
|
+
const ids = this.byAgent.get(agentId);
|
|
187
|
+
if (!ids)
|
|
188
|
+
return [];
|
|
189
|
+
return [...ids]
|
|
190
|
+
.map((id) => this.disputes.get(id))
|
|
191
|
+
.filter((d) => d !== undefined);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Query disputes with filtering.
|
|
195
|
+
*/
|
|
196
|
+
query(filter) {
|
|
197
|
+
let results = [...this.disputes.values()];
|
|
198
|
+
if (filter.status) {
|
|
199
|
+
results = results.filter((d) => d.status === filter.status);
|
|
200
|
+
}
|
|
201
|
+
if (filter.agentId) {
|
|
202
|
+
results = results.filter((d) => d.agentId === filter.agentId);
|
|
203
|
+
}
|
|
204
|
+
if (filter.transactionId) {
|
|
205
|
+
results = results.filter((d) => d.transactionId === filter.transactionId);
|
|
206
|
+
}
|
|
207
|
+
if (filter.liability) {
|
|
208
|
+
results = results.filter((d) => d.liability === filter.liability);
|
|
209
|
+
}
|
|
210
|
+
// Sort newest first
|
|
211
|
+
results.sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
212
|
+
if (filter.limit) {
|
|
213
|
+
results = results.slice(0, filter.limit);
|
|
214
|
+
}
|
|
215
|
+
return results;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Register a listener for dispute status changes.
|
|
219
|
+
*/
|
|
220
|
+
onStatusChange(listener) {
|
|
221
|
+
this.listeners.push(listener);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Get summary statistics for disputes.
|
|
225
|
+
*/
|
|
226
|
+
getStats() {
|
|
227
|
+
let open = 0;
|
|
228
|
+
let investigating = 0;
|
|
229
|
+
let resolved = 0;
|
|
230
|
+
let escalated = 0;
|
|
231
|
+
let totalRequestedAmount = 0;
|
|
232
|
+
let totalResolvedAmount = 0;
|
|
233
|
+
for (const dispute of this.disputes.values()) {
|
|
234
|
+
totalRequestedAmount += dispute.requestedAmount;
|
|
235
|
+
totalResolvedAmount += dispute.resolvedAmount ?? 0;
|
|
236
|
+
switch (dispute.status) {
|
|
237
|
+
case 'open':
|
|
238
|
+
open++;
|
|
239
|
+
break;
|
|
240
|
+
case 'investigating':
|
|
241
|
+
investigating++;
|
|
242
|
+
break;
|
|
243
|
+
case 'resolved_refunded':
|
|
244
|
+
case 'resolved_denied':
|
|
245
|
+
case 'resolved_partial':
|
|
246
|
+
resolved++;
|
|
247
|
+
break;
|
|
248
|
+
case 'escalated':
|
|
249
|
+
escalated++;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return {
|
|
254
|
+
total: this.disputes.size,
|
|
255
|
+
open,
|
|
256
|
+
investigating,
|
|
257
|
+
resolved,
|
|
258
|
+
escalated,
|
|
259
|
+
totalRequestedAmount,
|
|
260
|
+
totalResolvedAmount,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
// ---------------------------------------------------------------------------
|
|
264
|
+
// Private
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
isClosed(status) {
|
|
267
|
+
return (status === 'resolved_refunded' ||
|
|
268
|
+
status === 'resolved_denied' ||
|
|
269
|
+
status === 'resolved_partial');
|
|
270
|
+
}
|
|
271
|
+
notifyListeners(dispute, previousStatus) {
|
|
272
|
+
for (const listener of this.listeners) {
|
|
273
|
+
try {
|
|
274
|
+
void listener(dispute, previousStatus);
|
|
275
|
+
}
|
|
276
|
+
catch (err) {
|
|
277
|
+
this.logger?.error(`[DisputeManager] Listener error: ${err}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
//# sourceMappingURL=disputes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"disputes.js","sourceRoot":"","sources":["../src/disputes.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { TransactionProvenance } from './provenance.js';
|
|
2
|
+
export { DisputeManager } from './disputes.js';
|
|
3
|
+
export type { FileDisputeInput, DisputeFilter, DisputeListener } from './disputes.js';
|
|
4
|
+
export { RecoveryEngine } from './recovery.js';
|
|
5
|
+
export type { RecoveryAction, RecoveryStatus, RecoveryType, RefundExecutor, } from './recovery.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEtF,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACV,cAAc,EACd,cAAc,EACd,YAAY,EACZ,cAAc,GACf,MAAM,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// @paysentry/protect — Public API
|
|
3
|
+
// Dispute resolution and recovery for AI agent payments
|
|
4
|
+
// =============================================================================
|
|
5
|
+
export { TransactionProvenance } from './provenance.js';
|
|
6
|
+
export { DisputeManager } from './disputes.js';
|
|
7
|
+
export { RecoveryEngine } from './recovery.js';
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,kCAAkC;AAClC,wDAAwD;AACxD,gFAAgF;AAEhF,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAG/C,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { AgentTransaction, TransactionId, ProvenanceRecord, Logger } from '@paysentry/core';
|
|
2
|
+
/**
|
|
3
|
+
* TransactionProvenance maintains a complete, immutable audit trail
|
|
4
|
+
* for every transaction. Each stage of the pipeline (intent, policy check,
|
|
5
|
+
* approval, execution, settlement, dispute) creates a provenance record.
|
|
6
|
+
*
|
|
7
|
+
* This forms the evidentiary basis for dispute resolution and liability
|
|
8
|
+
* attribution.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const provenance = new TransactionProvenance();
|
|
13
|
+
*
|
|
14
|
+
* // Record each stage
|
|
15
|
+
* provenance.recordIntent(tx, { originalPrompt: 'Buy me a coffee' });
|
|
16
|
+
* provenance.recordPolicyCheck(tx.id, 'pass', { policyId: 'default' });
|
|
17
|
+
* provenance.recordExecution(tx.id, 'pass', { txHash: '0xabc...' });
|
|
18
|
+
* provenance.recordSettlement(tx.id, 'pass', { confirmedAt: '2026-01-01' });
|
|
19
|
+
*
|
|
20
|
+
* // Query the full chain
|
|
21
|
+
* const chain = provenance.getChain(tx.id);
|
|
22
|
+
* // chain = [intent, policy_check, execution, settlement]
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class TransactionProvenance {
|
|
26
|
+
/** Storage: transactionId -> ordered list of provenance records */
|
|
27
|
+
private readonly chains;
|
|
28
|
+
private readonly logger?;
|
|
29
|
+
constructor(options?: {
|
|
30
|
+
logger?: Logger;
|
|
31
|
+
});
|
|
32
|
+
/**
|
|
33
|
+
* Record the initial intent stage — when the agent declares what it wants to pay.
|
|
34
|
+
*/
|
|
35
|
+
recordIntent(tx: AgentTransaction, details?: Record<string, unknown>): ProvenanceRecord;
|
|
36
|
+
/**
|
|
37
|
+
* Record a policy check stage — whether the policy engine approved/denied.
|
|
38
|
+
*/
|
|
39
|
+
recordPolicyCheck(txId: TransactionId, outcome: 'pass' | 'fail', details?: Record<string, unknown>): ProvenanceRecord;
|
|
40
|
+
/**
|
|
41
|
+
* Record an approval stage — human or automated approval decision.
|
|
42
|
+
*/
|
|
43
|
+
recordApproval(txId: TransactionId, outcome: 'pass' | 'fail', details?: Record<string, unknown>): ProvenanceRecord;
|
|
44
|
+
/**
|
|
45
|
+
* Record the execution stage — when the payment is actually submitted.
|
|
46
|
+
*/
|
|
47
|
+
recordExecution(txId: TransactionId, outcome: 'pass' | 'fail', details?: Record<string, unknown>): ProvenanceRecord;
|
|
48
|
+
/**
|
|
49
|
+
* Record the settlement stage — when funds are confirmed received.
|
|
50
|
+
*/
|
|
51
|
+
recordSettlement(txId: TransactionId, outcome: 'pass' | 'fail', details?: Record<string, unknown>): ProvenanceRecord;
|
|
52
|
+
/**
|
|
53
|
+
* Record a dispute stage — when a dispute is filed against this transaction.
|
|
54
|
+
*/
|
|
55
|
+
recordDispute(txId: TransactionId, details?: Record<string, unknown>): ProvenanceRecord;
|
|
56
|
+
/**
|
|
57
|
+
* Get the full provenance chain for a transaction.
|
|
58
|
+
* Returns records in chronological order.
|
|
59
|
+
*/
|
|
60
|
+
getChain(txId: TransactionId): readonly ProvenanceRecord[];
|
|
61
|
+
/**
|
|
62
|
+
* Check if a transaction has a complete provenance chain
|
|
63
|
+
* (intent through settlement or dispute).
|
|
64
|
+
*/
|
|
65
|
+
isComplete(txId: TransactionId): boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Get the last recorded stage for a transaction.
|
|
68
|
+
*/
|
|
69
|
+
getLastStage(txId: TransactionId): ProvenanceRecord | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Get all transaction IDs with provenance records.
|
|
72
|
+
*/
|
|
73
|
+
get transactionIds(): TransactionId[];
|
|
74
|
+
/**
|
|
75
|
+
* Get the total number of provenance records across all transactions.
|
|
76
|
+
*/
|
|
77
|
+
get totalRecords(): number;
|
|
78
|
+
private addRecord;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,gBAAgB,EAChB,MAAM,EACP,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,qBAAqB;IAChC,mEAAmE;IACnE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqD;IAE5E,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;gBAErB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAIzC;;OAEG;IACH,YAAY,CACV,EAAE,EAAE,gBAAgB,EACpB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,gBAAgB;IAmBnB;;OAEG;IACH,iBAAiB,CACf,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,gBAAgB;IAWnB;;OAEG;IACH,cAAc,CACZ,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,gBAAgB;IAWnB;;OAEG;IACH,eAAe,CACb,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,gBAAgB;IAWnB;;OAEG;IACH,gBAAgB,CACd,IAAI,EAAE,aAAa,EACnB,OAAO,EAAE,MAAM,GAAG,MAAM,EACxB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,gBAAgB;IAWnB;;OAEG;IACH,aAAa,CACX,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GACpC,gBAAgB;IAWnB;;;OAGG;IACH,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,SAAS,gBAAgB,EAAE;IAI1D;;;OAGG;IACH,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO;IAQxC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,aAAa,GAAG,gBAAgB,GAAG,SAAS;IAM/D;;OAEG;IACH,IAAI,cAAc,IAAI,aAAa,EAAE,CAEpC;IAED;;OAEG;IACH,IAAI,YAAY,IAAI,MAAM,CAMzB;IAMD,OAAO,CAAC,SAAS;CAclB"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// TransactionProvenance — Full audit trail from intent to settlement
|
|
3
|
+
// Records every step of the transaction lifecycle for accountability
|
|
4
|
+
// =============================================================================
|
|
5
|
+
/**
|
|
6
|
+
* TransactionProvenance maintains a complete, immutable audit trail
|
|
7
|
+
* for every transaction. Each stage of the pipeline (intent, policy check,
|
|
8
|
+
* approval, execution, settlement, dispute) creates a provenance record.
|
|
9
|
+
*
|
|
10
|
+
* This forms the evidentiary basis for dispute resolution and liability
|
|
11
|
+
* attribution.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const provenance = new TransactionProvenance();
|
|
16
|
+
*
|
|
17
|
+
* // Record each stage
|
|
18
|
+
* provenance.recordIntent(tx, { originalPrompt: 'Buy me a coffee' });
|
|
19
|
+
* provenance.recordPolicyCheck(tx.id, 'pass', { policyId: 'default' });
|
|
20
|
+
* provenance.recordExecution(tx.id, 'pass', { txHash: '0xabc...' });
|
|
21
|
+
* provenance.recordSettlement(tx.id, 'pass', { confirmedAt: '2026-01-01' });
|
|
22
|
+
*
|
|
23
|
+
* // Query the full chain
|
|
24
|
+
* const chain = provenance.getChain(tx.id);
|
|
25
|
+
* // chain = [intent, policy_check, execution, settlement]
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export class TransactionProvenance {
|
|
29
|
+
/** Storage: transactionId -> ordered list of provenance records */
|
|
30
|
+
chains = new Map();
|
|
31
|
+
logger;
|
|
32
|
+
constructor(options) {
|
|
33
|
+
this.logger = options?.logger;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Record the initial intent stage — when the agent declares what it wants to pay.
|
|
37
|
+
*/
|
|
38
|
+
recordIntent(tx, details = {}) {
|
|
39
|
+
return this.addRecord(tx.id, {
|
|
40
|
+
transactionId: tx.id,
|
|
41
|
+
stage: 'intent',
|
|
42
|
+
timestamp: new Date().toISOString(),
|
|
43
|
+
action: `Agent ${tx.agentId} intends to pay ${tx.amount} ${tx.currency} to ${tx.recipient}`,
|
|
44
|
+
outcome: 'pass',
|
|
45
|
+
details: {
|
|
46
|
+
agentId: tx.agentId,
|
|
47
|
+
recipient: tx.recipient,
|
|
48
|
+
amount: tx.amount,
|
|
49
|
+
currency: tx.currency,
|
|
50
|
+
purpose: tx.purpose,
|
|
51
|
+
protocol: tx.protocol,
|
|
52
|
+
...details,
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Record a policy check stage — whether the policy engine approved/denied.
|
|
58
|
+
*/
|
|
59
|
+
recordPolicyCheck(txId, outcome, details = {}) {
|
|
60
|
+
return this.addRecord(txId, {
|
|
61
|
+
transactionId: txId,
|
|
62
|
+
stage: 'policy_check',
|
|
63
|
+
timestamp: new Date().toISOString(),
|
|
64
|
+
action: outcome === 'pass' ? 'Policy check passed' : 'Policy check failed',
|
|
65
|
+
outcome,
|
|
66
|
+
details,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Record an approval stage — human or automated approval decision.
|
|
71
|
+
*/
|
|
72
|
+
recordApproval(txId, outcome, details = {}) {
|
|
73
|
+
return this.addRecord(txId, {
|
|
74
|
+
transactionId: txId,
|
|
75
|
+
stage: 'approval',
|
|
76
|
+
timestamp: new Date().toISOString(),
|
|
77
|
+
action: outcome === 'pass' ? 'Transaction approved' : 'Transaction rejected',
|
|
78
|
+
outcome,
|
|
79
|
+
details,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Record the execution stage — when the payment is actually submitted.
|
|
84
|
+
*/
|
|
85
|
+
recordExecution(txId, outcome, details = {}) {
|
|
86
|
+
return this.addRecord(txId, {
|
|
87
|
+
transactionId: txId,
|
|
88
|
+
stage: 'execution',
|
|
89
|
+
timestamp: new Date().toISOString(),
|
|
90
|
+
action: outcome === 'pass' ? 'Payment executed successfully' : 'Payment execution failed',
|
|
91
|
+
outcome,
|
|
92
|
+
details,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Record the settlement stage — when funds are confirmed received.
|
|
97
|
+
*/
|
|
98
|
+
recordSettlement(txId, outcome, details = {}) {
|
|
99
|
+
return this.addRecord(txId, {
|
|
100
|
+
transactionId: txId,
|
|
101
|
+
stage: 'settlement',
|
|
102
|
+
timestamp: new Date().toISOString(),
|
|
103
|
+
action: outcome === 'pass' ? 'Payment settled and confirmed' : 'Settlement failed',
|
|
104
|
+
outcome,
|
|
105
|
+
details,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Record a dispute stage — when a dispute is filed against this transaction.
|
|
110
|
+
*/
|
|
111
|
+
recordDispute(txId, details = {}) {
|
|
112
|
+
return this.addRecord(txId, {
|
|
113
|
+
transactionId: txId,
|
|
114
|
+
stage: 'dispute',
|
|
115
|
+
timestamp: new Date().toISOString(),
|
|
116
|
+
action: 'Dispute filed against transaction',
|
|
117
|
+
outcome: 'pending',
|
|
118
|
+
details,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Get the full provenance chain for a transaction.
|
|
123
|
+
* Returns records in chronological order.
|
|
124
|
+
*/
|
|
125
|
+
getChain(txId) {
|
|
126
|
+
return this.chains.get(txId) ?? [];
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Check if a transaction has a complete provenance chain
|
|
130
|
+
* (intent through settlement or dispute).
|
|
131
|
+
*/
|
|
132
|
+
isComplete(txId) {
|
|
133
|
+
const chain = this.chains.get(txId);
|
|
134
|
+
if (!chain || chain.length === 0)
|
|
135
|
+
return false;
|
|
136
|
+
const stages = new Set(chain.map((r) => r.stage));
|
|
137
|
+
return stages.has('intent') && (stages.has('settlement') || stages.has('dispute'));
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Get the last recorded stage for a transaction.
|
|
141
|
+
*/
|
|
142
|
+
getLastStage(txId) {
|
|
143
|
+
const chain = this.chains.get(txId);
|
|
144
|
+
if (!chain || chain.length === 0)
|
|
145
|
+
return undefined;
|
|
146
|
+
return chain[chain.length - 1];
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Get all transaction IDs with provenance records.
|
|
150
|
+
*/
|
|
151
|
+
get transactionIds() {
|
|
152
|
+
return [...this.chains.keys()];
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Get the total number of provenance records across all transactions.
|
|
156
|
+
*/
|
|
157
|
+
get totalRecords() {
|
|
158
|
+
let total = 0;
|
|
159
|
+
for (const chain of this.chains.values()) {
|
|
160
|
+
total += chain.length;
|
|
161
|
+
}
|
|
162
|
+
return total;
|
|
163
|
+
}
|
|
164
|
+
// ---------------------------------------------------------------------------
|
|
165
|
+
// Private
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
addRecord(txId, record) {
|
|
168
|
+
let chain = this.chains.get(txId);
|
|
169
|
+
if (!chain) {
|
|
170
|
+
chain = [];
|
|
171
|
+
this.chains.set(txId, chain);
|
|
172
|
+
}
|
|
173
|
+
chain.push(record);
|
|
174
|
+
this.logger?.info(`[Provenance] ${record.stage}:${record.outcome} for ${txId}`, {
|
|
175
|
+
action: record.action,
|
|
176
|
+
});
|
|
177
|
+
return record;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=provenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.js","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { DisputeId, TransactionId, AgentId, Logger } from '@paysentry/core';
|
|
2
|
+
import type { DisputeManager } from './disputes.js';
|
|
3
|
+
/** Status of a recovery attempt */
|
|
4
|
+
export type RecoveryStatus = 'pending' | 'processing' | 'completed' | 'failed' | 'cancelled';
|
|
5
|
+
/** Type of recovery action */
|
|
6
|
+
export type RecoveryType = 'full_refund' | 'partial_refund' | 'chargeback' | 'credit';
|
|
7
|
+
/** A single recovery action */
|
|
8
|
+
export interface RecoveryAction {
|
|
9
|
+
/** Unique recovery ID */
|
|
10
|
+
readonly id: string;
|
|
11
|
+
/** Associated dispute */
|
|
12
|
+
readonly disputeId: DisputeId;
|
|
13
|
+
/** Original transaction */
|
|
14
|
+
readonly transactionId: TransactionId;
|
|
15
|
+
/** Agent receiving the recovery */
|
|
16
|
+
readonly agentId: AgentId;
|
|
17
|
+
/** Type of recovery */
|
|
18
|
+
readonly type: RecoveryType;
|
|
19
|
+
/** Amount to recover */
|
|
20
|
+
readonly amount: number;
|
|
21
|
+
/** Currency */
|
|
22
|
+
readonly currency: string;
|
|
23
|
+
/** Current status */
|
|
24
|
+
status: RecoveryStatus;
|
|
25
|
+
/** ISO 8601 timestamp of creation */
|
|
26
|
+
readonly createdAt: string;
|
|
27
|
+
/** ISO 8601 timestamp of last update */
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
/** ISO 8601 timestamp of completion */
|
|
30
|
+
completedAt?: string;
|
|
31
|
+
/** Protocol-specific refund transaction ID */
|
|
32
|
+
refundTxId?: string;
|
|
33
|
+
/** Error message if failed */
|
|
34
|
+
error?: string;
|
|
35
|
+
}
|
|
36
|
+
/** Handler that executes the actual refund on the protocol level */
|
|
37
|
+
export type RefundExecutor = (action: RecoveryAction) => Promise<{
|
|
38
|
+
success: boolean;
|
|
39
|
+
refundTxId?: string;
|
|
40
|
+
error?: string;
|
|
41
|
+
}>;
|
|
42
|
+
/**
|
|
43
|
+
* RecoveryEngine automates the process of recovering funds after
|
|
44
|
+
* a dispute has been resolved in favor of the agent. It manages
|
|
45
|
+
* refund queues, retry logic, and settlement confirmation.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* const recovery = new RecoveryEngine({
|
|
50
|
+
* disputes: disputeManager,
|
|
51
|
+
* executor: async (action) => {
|
|
52
|
+
* // Execute the actual refund via the payment protocol
|
|
53
|
+
* const result = await protocolRefund(action.transactionId, action.amount);
|
|
54
|
+
* return { success: result.ok, refundTxId: result.txId };
|
|
55
|
+
* },
|
|
56
|
+
* });
|
|
57
|
+
*
|
|
58
|
+
* // Initiate recovery for a resolved dispute
|
|
59
|
+
* const action = recovery.initiate(dispute.id);
|
|
60
|
+
*
|
|
61
|
+
* // Process the recovery queue
|
|
62
|
+
* await recovery.processQueue();
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare class RecoveryEngine {
|
|
66
|
+
/** All recovery actions */
|
|
67
|
+
private readonly actions;
|
|
68
|
+
/** Index: disputeId -> recoveryId */
|
|
69
|
+
private readonly byDispute;
|
|
70
|
+
/** Processing queue (FIFO) */
|
|
71
|
+
private readonly queue;
|
|
72
|
+
/** Maximum retry attempts */
|
|
73
|
+
private readonly maxRetries;
|
|
74
|
+
/** Retry delay in milliseconds */
|
|
75
|
+
private readonly retryDelayMs;
|
|
76
|
+
private readonly disputes;
|
|
77
|
+
private readonly executor;
|
|
78
|
+
private readonly logger?;
|
|
79
|
+
constructor(options: {
|
|
80
|
+
disputes: DisputeManager;
|
|
81
|
+
executor: RefundExecutor;
|
|
82
|
+
maxRetries?: number;
|
|
83
|
+
retryDelayMs?: number;
|
|
84
|
+
logger?: Logger;
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* Initiate a recovery action for a resolved dispute.
|
|
88
|
+
* The dispute must be in a resolved state that warrants a refund.
|
|
89
|
+
*/
|
|
90
|
+
initiate(disputeId: DisputeId): RecoveryAction;
|
|
91
|
+
/**
|
|
92
|
+
* Process all pending recovery actions in the queue.
|
|
93
|
+
* Each action is attempted with retry logic.
|
|
94
|
+
*/
|
|
95
|
+
processQueue(): Promise<RecoveryAction[]>;
|
|
96
|
+
/**
|
|
97
|
+
* Cancel a pending recovery action.
|
|
98
|
+
*/
|
|
99
|
+
cancel(recoveryId: string): RecoveryAction;
|
|
100
|
+
/**
|
|
101
|
+
* Get a recovery action by ID.
|
|
102
|
+
*/
|
|
103
|
+
get(recoveryId: string): RecoveryAction | undefined;
|
|
104
|
+
/**
|
|
105
|
+
* Get the recovery action for a specific dispute.
|
|
106
|
+
*/
|
|
107
|
+
getByDispute(disputeId: DisputeId): RecoveryAction | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Get all recovery actions, optionally filtered by status.
|
|
110
|
+
*/
|
|
111
|
+
getAll(status?: RecoveryStatus): RecoveryAction[];
|
|
112
|
+
/**
|
|
113
|
+
* Get recovery statistics.
|
|
114
|
+
*/
|
|
115
|
+
getStats(): {
|
|
116
|
+
total: number;
|
|
117
|
+
pending: number;
|
|
118
|
+
processing: number;
|
|
119
|
+
completed: number;
|
|
120
|
+
failed: number;
|
|
121
|
+
cancelled: number;
|
|
122
|
+
totalRecovered: number;
|
|
123
|
+
};
|
|
124
|
+
private executeWithRetry;
|
|
125
|
+
private sleep;
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=recovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.d.ts","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"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"}
|
package/dist/recovery.js
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
// =============================================================================
|
|
2
|
+
// RecoveryEngine — Automated refund and chargeback flows
|
|
3
|
+
// Handles the mechanical process of recovering funds after dispute resolution
|
|
4
|
+
// =============================================================================
|
|
5
|
+
import { generateId } from '@paysentry/core';
|
|
6
|
+
/**
|
|
7
|
+
* RecoveryEngine automates the process of recovering funds after
|
|
8
|
+
* a dispute has been resolved in favor of the agent. It manages
|
|
9
|
+
* refund queues, retry logic, and settlement confirmation.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```ts
|
|
13
|
+
* const recovery = new RecoveryEngine({
|
|
14
|
+
* disputes: disputeManager,
|
|
15
|
+
* executor: async (action) => {
|
|
16
|
+
* // Execute the actual refund via the payment protocol
|
|
17
|
+
* const result = await protocolRefund(action.transactionId, action.amount);
|
|
18
|
+
* return { success: result.ok, refundTxId: result.txId };
|
|
19
|
+
* },
|
|
20
|
+
* });
|
|
21
|
+
*
|
|
22
|
+
* // Initiate recovery for a resolved dispute
|
|
23
|
+
* const action = recovery.initiate(dispute.id);
|
|
24
|
+
*
|
|
25
|
+
* // Process the recovery queue
|
|
26
|
+
* await recovery.processQueue();
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export class RecoveryEngine {
|
|
30
|
+
/** All recovery actions */
|
|
31
|
+
actions = new Map();
|
|
32
|
+
/** Index: disputeId -> recoveryId */
|
|
33
|
+
byDispute = new Map();
|
|
34
|
+
/** Processing queue (FIFO) */
|
|
35
|
+
queue = [];
|
|
36
|
+
/** Maximum retry attempts */
|
|
37
|
+
maxRetries;
|
|
38
|
+
/** Retry delay in milliseconds */
|
|
39
|
+
retryDelayMs;
|
|
40
|
+
disputes;
|
|
41
|
+
executor;
|
|
42
|
+
logger;
|
|
43
|
+
constructor(options) {
|
|
44
|
+
this.disputes = options.disputes;
|
|
45
|
+
this.executor = options.executor;
|
|
46
|
+
this.maxRetries = options.maxRetries ?? 3;
|
|
47
|
+
this.retryDelayMs = options.retryDelayMs ?? 5000;
|
|
48
|
+
this.logger = options.logger;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Initiate a recovery action for a resolved dispute.
|
|
52
|
+
* The dispute must be in a resolved state that warrants a refund.
|
|
53
|
+
*/
|
|
54
|
+
initiate(disputeId) {
|
|
55
|
+
const dispute = this.disputes.get(disputeId);
|
|
56
|
+
if (!dispute) {
|
|
57
|
+
throw new Error(`Dispute ${disputeId} not found`);
|
|
58
|
+
}
|
|
59
|
+
if (dispute.status !== 'resolved_refunded' && dispute.status !== 'resolved_partial') {
|
|
60
|
+
throw new Error(`Cannot initiate recovery for dispute ${disputeId} with status "${dispute.status}". ` +
|
|
61
|
+
`Dispute must be resolved with refund or partial refund.`);
|
|
62
|
+
}
|
|
63
|
+
// Check for existing recovery
|
|
64
|
+
const existingId = this.byDispute.get(disputeId);
|
|
65
|
+
if (existingId) {
|
|
66
|
+
const existing = this.actions.get(existingId);
|
|
67
|
+
if (existing && existing.status !== 'failed' && existing.status !== 'cancelled') {
|
|
68
|
+
throw new Error(`Active recovery ${existingId} already exists for dispute ${disputeId}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
const amount = dispute.resolvedAmount ?? dispute.requestedAmount;
|
|
72
|
+
const recoveryType = dispute.status === 'resolved_partial' ? 'partial_refund' : 'full_refund';
|
|
73
|
+
const now = new Date().toISOString();
|
|
74
|
+
const action = {
|
|
75
|
+
id: generateId('rcv'),
|
|
76
|
+
disputeId,
|
|
77
|
+
transactionId: dispute.transactionId,
|
|
78
|
+
agentId: dispute.agentId,
|
|
79
|
+
type: recoveryType,
|
|
80
|
+
amount,
|
|
81
|
+
currency: 'USDC', // Default; could be pulled from transaction
|
|
82
|
+
status: 'pending',
|
|
83
|
+
createdAt: now,
|
|
84
|
+
updatedAt: now,
|
|
85
|
+
};
|
|
86
|
+
this.actions.set(action.id, action);
|
|
87
|
+
this.byDispute.set(disputeId, action.id);
|
|
88
|
+
this.queue.push(action.id);
|
|
89
|
+
this.logger?.info(`[RecoveryEngine] Initiated ${recoveryType} of $${amount} for dispute ${disputeId}`);
|
|
90
|
+
return action;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Process all pending recovery actions in the queue.
|
|
94
|
+
* Each action is attempted with retry logic.
|
|
95
|
+
*/
|
|
96
|
+
async processQueue() {
|
|
97
|
+
const processed = [];
|
|
98
|
+
while (this.queue.length > 0) {
|
|
99
|
+
const actionId = this.queue.shift();
|
|
100
|
+
const action = this.actions.get(actionId);
|
|
101
|
+
if (!action || action.status === 'cancelled')
|
|
102
|
+
continue;
|
|
103
|
+
const result = await this.executeWithRetry(action);
|
|
104
|
+
processed.push(result);
|
|
105
|
+
}
|
|
106
|
+
return processed;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Cancel a pending recovery action.
|
|
110
|
+
*/
|
|
111
|
+
cancel(recoveryId) {
|
|
112
|
+
const action = this.actions.get(recoveryId);
|
|
113
|
+
if (!action) {
|
|
114
|
+
throw new Error(`Recovery action ${recoveryId} not found`);
|
|
115
|
+
}
|
|
116
|
+
if (action.status !== 'pending') {
|
|
117
|
+
throw new Error(`Cannot cancel recovery ${recoveryId} with status "${action.status}"`);
|
|
118
|
+
}
|
|
119
|
+
action.status = 'cancelled';
|
|
120
|
+
action.updatedAt = new Date().toISOString();
|
|
121
|
+
this.logger?.info(`[RecoveryEngine] Cancelled recovery ${recoveryId}`);
|
|
122
|
+
return action;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Get a recovery action by ID.
|
|
126
|
+
*/
|
|
127
|
+
get(recoveryId) {
|
|
128
|
+
return this.actions.get(recoveryId);
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Get the recovery action for a specific dispute.
|
|
132
|
+
*/
|
|
133
|
+
getByDispute(disputeId) {
|
|
134
|
+
const recoveryId = this.byDispute.get(disputeId);
|
|
135
|
+
return recoveryId ? this.actions.get(recoveryId) : undefined;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Get all recovery actions, optionally filtered by status.
|
|
139
|
+
*/
|
|
140
|
+
getAll(status) {
|
|
141
|
+
const all = [...this.actions.values()];
|
|
142
|
+
return status ? all.filter((a) => a.status === status) : all;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Get recovery statistics.
|
|
146
|
+
*/
|
|
147
|
+
getStats() {
|
|
148
|
+
let pending = 0;
|
|
149
|
+
let processing = 0;
|
|
150
|
+
let completed = 0;
|
|
151
|
+
let failed = 0;
|
|
152
|
+
let cancelled = 0;
|
|
153
|
+
let totalRecovered = 0;
|
|
154
|
+
for (const action of this.actions.values()) {
|
|
155
|
+
switch (action.status) {
|
|
156
|
+
case 'pending':
|
|
157
|
+
pending++;
|
|
158
|
+
break;
|
|
159
|
+
case 'processing':
|
|
160
|
+
processing++;
|
|
161
|
+
break;
|
|
162
|
+
case 'completed':
|
|
163
|
+
completed++;
|
|
164
|
+
totalRecovered += action.amount;
|
|
165
|
+
break;
|
|
166
|
+
case 'failed':
|
|
167
|
+
failed++;
|
|
168
|
+
break;
|
|
169
|
+
case 'cancelled':
|
|
170
|
+
cancelled++;
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return {
|
|
175
|
+
total: this.actions.size,
|
|
176
|
+
pending,
|
|
177
|
+
processing,
|
|
178
|
+
completed,
|
|
179
|
+
failed,
|
|
180
|
+
cancelled,
|
|
181
|
+
totalRecovered,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
// ---------------------------------------------------------------------------
|
|
185
|
+
// Private
|
|
186
|
+
// ---------------------------------------------------------------------------
|
|
187
|
+
async executeWithRetry(action) {
|
|
188
|
+
action.status = 'processing';
|
|
189
|
+
action.updatedAt = new Date().toISOString();
|
|
190
|
+
for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
|
|
191
|
+
this.logger?.info(`[RecoveryEngine] Executing recovery ${action.id}, attempt ${attempt}/${this.maxRetries}`);
|
|
192
|
+
try {
|
|
193
|
+
const result = await this.executor(action);
|
|
194
|
+
if (result.success) {
|
|
195
|
+
action.status = 'completed';
|
|
196
|
+
action.refundTxId = result.refundTxId;
|
|
197
|
+
action.completedAt = new Date().toISOString();
|
|
198
|
+
action.updatedAt = action.completedAt;
|
|
199
|
+
this.logger?.info(`[RecoveryEngine] Recovery ${action.id} completed: refundTxId=${result.refundTxId}`);
|
|
200
|
+
return action;
|
|
201
|
+
}
|
|
202
|
+
action.error = result.error ?? 'Refund execution returned failure';
|
|
203
|
+
}
|
|
204
|
+
catch (err) {
|
|
205
|
+
action.error = err instanceof Error ? err.message : String(err);
|
|
206
|
+
}
|
|
207
|
+
// Wait before retrying (skip wait on last attempt)
|
|
208
|
+
if (attempt < this.maxRetries) {
|
|
209
|
+
await this.sleep(this.retryDelayMs * attempt);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
// All retries exhausted
|
|
213
|
+
action.status = 'failed';
|
|
214
|
+
action.updatedAt = new Date().toISOString();
|
|
215
|
+
this.logger?.error(`[RecoveryEngine] Recovery ${action.id} failed after ${this.maxRetries} attempts: ${action.error}`);
|
|
216
|
+
return action;
|
|
217
|
+
}
|
|
218
|
+
sleep(ms) {
|
|
219
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=recovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recovery.js","sourceRoot":"","sources":["../src/recovery.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@paysentry/protect",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Dispute resolution and recovery for AI agent payments",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"clean": "tsc --build --clean"
|
|
17
|
+
},
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@paysentry/core": "1.0.0"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"files": ["dist"],
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "https://github.com/paysentry/paysentry",
|
|
26
|
+
"directory": "packages/protect"
|
|
27
|
+
}
|
|
28
|
+
}
|