@profullstack/coinpay 0.5.0 → 0.5.1
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/bin/coinpay.js +161 -0
- package/package.json +1 -1
- package/src/index.d.ts +4 -5
- package/src/index.js +1 -0
- package/src/reputation.d.ts +45 -43
- package/src/reputation.js +30 -17
package/bin/coinpay.js
CHANGED
|
@@ -218,6 +218,13 @@ ${colors.cyan}Commands:${colors.reset}
|
|
|
218
218
|
events <id> Get escrow audit log
|
|
219
219
|
auth <id> Authenticate with escrow token
|
|
220
220
|
|
|
221
|
+
${colors.bright}reputation${colors.reset}
|
|
222
|
+
submit Submit a task receipt
|
|
223
|
+
query <agent-did> Query agent reputation
|
|
224
|
+
credential <id> Get credential details
|
|
225
|
+
verify <id> Verify a credential
|
|
226
|
+
revocations List revoked credentials
|
|
227
|
+
|
|
221
228
|
${colors.bright}webhook${colors.reset}
|
|
222
229
|
logs <business-id> Get webhook logs
|
|
223
230
|
test <business-id> Send test webhook
|
|
@@ -1577,6 +1584,156 @@ async function handleEscrow(subcommand, args, flags) {
|
|
|
1577
1584
|
}
|
|
1578
1585
|
}
|
|
1579
1586
|
|
|
1587
|
+
/**
|
|
1588
|
+
* Reputation commands
|
|
1589
|
+
*/
|
|
1590
|
+
async function handleReputation(subcommand, args, flags) {
|
|
1591
|
+
switch (subcommand) {
|
|
1592
|
+
case 'submit': {
|
|
1593
|
+
const receiptArg = flags.receipt;
|
|
1594
|
+
if (!receiptArg) {
|
|
1595
|
+
print.error('Required: --receipt <json-file-or-inline-json>');
|
|
1596
|
+
print.info('Example: coinpay reputation submit --receipt receipt.json');
|
|
1597
|
+
print.info('Example: coinpay reputation submit --receipt \'{"receipt_id":"..."}\'');
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
let receipt;
|
|
1602
|
+
try {
|
|
1603
|
+
if (existsSync(receiptArg)) {
|
|
1604
|
+
receipt = JSON.parse(readFileSync(receiptArg, 'utf-8'));
|
|
1605
|
+
} else {
|
|
1606
|
+
receipt = JSON.parse(receiptArg);
|
|
1607
|
+
}
|
|
1608
|
+
} catch {
|
|
1609
|
+
print.error('Could not parse receipt JSON. Provide a valid JSON file path or inline JSON.');
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
const client = createClient();
|
|
1614
|
+
const { submitReceipt } = await import('../src/reputation.js');
|
|
1615
|
+
const result = await submitReceipt(client, receipt);
|
|
1616
|
+
|
|
1617
|
+
if (result.success) {
|
|
1618
|
+
print.success('Receipt submitted');
|
|
1619
|
+
} else {
|
|
1620
|
+
print.error(result.error || 'Submission failed');
|
|
1621
|
+
}
|
|
1622
|
+
|
|
1623
|
+
if (flags.json) print.json(result);
|
|
1624
|
+
else if (result.receipt) print.json(result.receipt);
|
|
1625
|
+
break;
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
case 'query': {
|
|
1629
|
+
const agentDid = args[0];
|
|
1630
|
+
if (!agentDid) {
|
|
1631
|
+
print.error('Agent DID required');
|
|
1632
|
+
print.info('Usage: coinpay reputation query <agent-did> [--window 30d|90d|all]');
|
|
1633
|
+
return;
|
|
1634
|
+
}
|
|
1635
|
+
|
|
1636
|
+
const client = createClient();
|
|
1637
|
+
const { getReputation } = await import('../src/reputation.js');
|
|
1638
|
+
const result = await getReputation(client, agentDid);
|
|
1639
|
+
|
|
1640
|
+
if (flags.json) {
|
|
1641
|
+
print.json(result);
|
|
1642
|
+
} else if (result.success && result.reputation) {
|
|
1643
|
+
const rep = result.reputation;
|
|
1644
|
+
const windowKey = flags.window === '90d' ? 'last_90_days'
|
|
1645
|
+
: flags.window === 'all' ? 'all_time'
|
|
1646
|
+
: 'last_30_days';
|
|
1647
|
+
const label = flags.window || '30d';
|
|
1648
|
+
const w = rep.windows[windowKey];
|
|
1649
|
+
|
|
1650
|
+
print.info(`Reputation for ${rep.agent_did} (${label}):`);
|
|
1651
|
+
console.log(` Tasks: ${w.task_count}`);
|
|
1652
|
+
console.log(` Accepted: ${w.accepted_count} (${(w.accepted_rate * 100).toFixed(1)}%)`);
|
|
1653
|
+
console.log(` Disputed: ${w.disputed_count} (${(w.dispute_rate * 100).toFixed(1)}%)`);
|
|
1654
|
+
console.log(` Volume: ${w.total_volume.toFixed(2)}`);
|
|
1655
|
+
console.log(` Avg Value: ${w.avg_task_value.toFixed(2)}`);
|
|
1656
|
+
console.log(` Unique Buyers: ${w.unique_buyers}`);
|
|
1657
|
+
|
|
1658
|
+
if (rep.anti_gaming.flagged) {
|
|
1659
|
+
print.warn(`Anti-gaming flags: ${rep.anti_gaming.flags.join(', ')}`);
|
|
1660
|
+
}
|
|
1661
|
+
} else {
|
|
1662
|
+
print.json(result);
|
|
1663
|
+
}
|
|
1664
|
+
break;
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
case 'credential': {
|
|
1668
|
+
const credentialId = args[0];
|
|
1669
|
+
if (!credentialId) {
|
|
1670
|
+
print.error('Credential ID required');
|
|
1671
|
+
print.info('Usage: coinpay reputation credential <credential-id>');
|
|
1672
|
+
return;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
const client = createClient();
|
|
1676
|
+
const { getCredential } = await import('../src/reputation.js');
|
|
1677
|
+
const result = await getCredential(client, credentialId);
|
|
1678
|
+
|
|
1679
|
+
if (result.success && result.credential) {
|
|
1680
|
+
print.success(`Credential ${result.credential.id}`);
|
|
1681
|
+
console.log(` Agent: ${result.credential.agent_did}`);
|
|
1682
|
+
console.log(` Type: ${result.credential.credential_type}`);
|
|
1683
|
+
console.log(` Issued: ${result.credential.issued_at}`);
|
|
1684
|
+
console.log(` Revoked: ${result.credential.revoked ? 'YES' : 'no'}`);
|
|
1685
|
+
}
|
|
1686
|
+
|
|
1687
|
+
if (flags.json) print.json(result);
|
|
1688
|
+
break;
|
|
1689
|
+
}
|
|
1690
|
+
|
|
1691
|
+
case 'verify': {
|
|
1692
|
+
const credentialId = args[0];
|
|
1693
|
+
if (!credentialId) {
|
|
1694
|
+
print.error('Credential ID required');
|
|
1695
|
+
print.info('Usage: coinpay reputation verify <credential-id>');
|
|
1696
|
+
return;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
const client = createClient();
|
|
1700
|
+
const { verifyCredential } = await import('../src/reputation.js');
|
|
1701
|
+
const result = await verifyCredential(client, { credential_id: credentialId });
|
|
1702
|
+
|
|
1703
|
+
if (result.valid) {
|
|
1704
|
+
print.success('Credential is valid');
|
|
1705
|
+
} else {
|
|
1706
|
+
print.error(`Credential invalid: ${result.reason}`);
|
|
1707
|
+
}
|
|
1708
|
+
|
|
1709
|
+
if (flags.json) print.json(result);
|
|
1710
|
+
break;
|
|
1711
|
+
}
|
|
1712
|
+
|
|
1713
|
+
case 'revocations': {
|
|
1714
|
+
const client = createClient();
|
|
1715
|
+
const { getRevocationList } = await import('../src/reputation.js');
|
|
1716
|
+
const result = await getRevocationList(client);
|
|
1717
|
+
|
|
1718
|
+
if (flags.json) {
|
|
1719
|
+
print.json(result);
|
|
1720
|
+
} else {
|
|
1721
|
+
const revocations = result.revocations || [];
|
|
1722
|
+
print.info(`Revoked credentials: ${revocations.length}`);
|
|
1723
|
+
for (const r of revocations) {
|
|
1724
|
+
console.log(` ${r.credential_id} — ${r.reason || 'no reason'} (${r.revoked_at})`);
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
break;
|
|
1728
|
+
}
|
|
1729
|
+
|
|
1730
|
+
default:
|
|
1731
|
+
print.error(`Unknown reputation command: ${subcommand}`);
|
|
1732
|
+
print.info('Available: submit, query, credential, verify, revocations');
|
|
1733
|
+
process.exit(1);
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
|
|
1580
1737
|
/**
|
|
1581
1738
|
* Main entry point
|
|
1582
1739
|
*/
|
|
@@ -1626,6 +1783,10 @@ async function main() {
|
|
|
1626
1783
|
case 'webhook':
|
|
1627
1784
|
await handleWebhook(subcommand, args, flags);
|
|
1628
1785
|
break;
|
|
1786
|
+
|
|
1787
|
+
case 'reputation':
|
|
1788
|
+
await handleReputation(subcommand, args, flags);
|
|
1789
|
+
break;
|
|
1629
1790
|
|
|
1630
1791
|
default:
|
|
1631
1792
|
print.error(`Unknown command: ${command}`);
|
package/package.json
CHANGED
package/src/index.d.ts
CHANGED
|
@@ -105,11 +105,10 @@ export {
|
|
|
105
105
|
getRevocationList,
|
|
106
106
|
} from './reputation.js';
|
|
107
107
|
export type {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
RevocationList,
|
|
108
|
+
ReceiptInput,
|
|
109
|
+
ReputationWindow,
|
|
110
|
+
ReputationResult,
|
|
111
|
+
Credential,
|
|
113
112
|
} from './reputation.js';
|
|
114
113
|
|
|
115
114
|
import { CoinPayClient } from './client.js';
|
package/src/index.js
CHANGED
package/src/reputation.d.ts
CHANGED
|
@@ -1,69 +1,71 @@
|
|
|
1
1
|
import { CoinPayClient } from './client';
|
|
2
2
|
|
|
3
|
-
export interface
|
|
3
|
+
export interface ReceiptInput {
|
|
4
4
|
receipt_id: string;
|
|
5
5
|
task_id: string;
|
|
6
6
|
agent_did: string;
|
|
7
7
|
buyer_did: string;
|
|
8
|
-
platform_did
|
|
8
|
+
platform_did?: string;
|
|
9
9
|
escrow_tx?: string;
|
|
10
|
-
amount
|
|
11
|
-
currency
|
|
10
|
+
amount?: number;
|
|
11
|
+
currency?: string;
|
|
12
12
|
category?: string;
|
|
13
13
|
sla?: Record<string, unknown>;
|
|
14
|
-
outcome: '
|
|
14
|
+
outcome: 'accepted' | 'rejected' | 'disputed';
|
|
15
15
|
dispute?: boolean;
|
|
16
16
|
artifact_hash?: string;
|
|
17
17
|
signatures: {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
escrow_sig: string;
|
|
19
|
+
agent_sig?: string;
|
|
20
|
+
buyer_sig?: string;
|
|
21
|
+
arbitration_sig?: string;
|
|
21
22
|
};
|
|
22
23
|
finalized_at?: string;
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export interface
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
failed: number;
|
|
30
|
-
disputed: number;
|
|
31
|
-
cancelled: number;
|
|
32
|
-
completion_rate: number;
|
|
33
|
-
dispute_rate: number;
|
|
26
|
+
export interface ReputationWindow {
|
|
27
|
+
task_count: number;
|
|
28
|
+
accepted_count: number;
|
|
29
|
+
disputed_count: number;
|
|
34
30
|
total_volume: number;
|
|
35
|
-
avg_task_value: number;
|
|
36
31
|
unique_buyers: number;
|
|
32
|
+
avg_task_value: number;
|
|
33
|
+
accepted_rate: number;
|
|
34
|
+
dispute_rate: number;
|
|
37
35
|
categories: Record<string, { count: number; volume: number }>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ReputationResult {
|
|
39
|
+
agent_did: string;
|
|
40
|
+
windows: {
|
|
41
|
+
last_30_days: ReputationWindow;
|
|
42
|
+
last_90_days: ReputationWindow;
|
|
43
|
+
all_time: ReputationWindow;
|
|
44
|
+
};
|
|
38
45
|
anti_gaming: {
|
|
39
|
-
circular_payment: boolean;
|
|
40
|
-
burst_detected: boolean;
|
|
41
|
-
below_economic_threshold: boolean;
|
|
42
|
-
insufficient_unique_buyers: boolean;
|
|
43
46
|
flagged: boolean;
|
|
44
|
-
|
|
47
|
+
flags: string[];
|
|
48
|
+
adjusted_weight: number;
|
|
45
49
|
};
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
export interface
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
revoked: string[];
|
|
62
|
-
details: Array<{ credential_id: string; reason: string; revoked_at: string }>;
|
|
52
|
+
export interface Credential {
|
|
53
|
+
id: string;
|
|
54
|
+
agent_did: string;
|
|
55
|
+
credential_type: string;
|
|
56
|
+
category?: string;
|
|
57
|
+
data: Record<string, unknown>;
|
|
58
|
+
window_start: string;
|
|
59
|
+
window_end: string;
|
|
60
|
+
issued_at: string;
|
|
61
|
+
issuer_did: string;
|
|
62
|
+
signature: string;
|
|
63
|
+
revoked: boolean;
|
|
64
|
+
revoked_at?: string;
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
export function submitReceipt(client: CoinPayClient, receipt:
|
|
66
|
-
export function getReputation(client: CoinPayClient, agentDid: string): Promise<
|
|
67
|
-
export function getCredential(client: CoinPayClient, credentialId: string): Promise<
|
|
68
|
-
export function verifyCredential(client: CoinPayClient,
|
|
69
|
-
export function getRevocationList(client: CoinPayClient): Promise<
|
|
67
|
+
export function submitReceipt(client: CoinPayClient, receipt: ReceiptInput): Promise<{ success: boolean; receipt?: Record<string, unknown>; error?: string }>;
|
|
68
|
+
export function getReputation(client: CoinPayClient, agentDid: string): Promise<{ success: boolean; reputation: ReputationResult }>;
|
|
69
|
+
export function getCredential(client: CoinPayClient, credentialId: string): Promise<{ success: boolean; credential: Credential }>;
|
|
70
|
+
export function verifyCredential(client: CoinPayClient, credential: { credential_id: string }): Promise<{ valid: boolean; reason?: string }>;
|
|
71
|
+
export function getRevocationList(client: CoinPayClient): Promise<{ success: boolean; revoked_credentials: string[]; revocations: Array<Record<string, unknown>> }>;
|
package/src/reputation.js
CHANGED
|
@@ -1,51 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reputation SDK Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
4
|
+
* Query and submit reputation data for the CoinPayPortal Reputation Protocol (CPR).
|
|
5
5
|
*
|
|
6
6
|
* @example
|
|
7
7
|
* import { CoinPayClient } from '@profullstack/coinpay';
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* // Submit a task receipt
|
|
11
|
-
* const result = await client.submitReceipt({ ... });
|
|
12
|
-
*
|
|
13
|
-
* // Get agent reputation
|
|
14
|
-
* const rep = await client.getReputation('did:web:agent.example.com');
|
|
8
|
+
* import { submitReceipt, getReputation } from '@profullstack/coinpay/reputation';
|
|
15
9
|
*/
|
|
16
10
|
|
|
17
11
|
/**
|
|
18
12
|
* Submit a task receipt
|
|
13
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
14
|
+
* @param {Object} receipt - Receipt data
|
|
15
|
+
* @returns {Promise<Object>}
|
|
19
16
|
*/
|
|
20
17
|
export async function submitReceipt(client, receipt) {
|
|
21
|
-
return client.
|
|
18
|
+
return client.request('/reputation/receipt', {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
body: JSON.stringify(receipt),
|
|
21
|
+
});
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Get
|
|
25
|
+
* Get reputation for an agent DID
|
|
26
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
27
|
+
* @param {string} agentDid
|
|
28
|
+
* @returns {Promise<Object>}
|
|
26
29
|
*/
|
|
27
30
|
export async function getReputation(client, agentDid) {
|
|
28
|
-
|
|
29
|
-
return client._request('GET', `/api/reputation/agent/${encoded}/reputation`);
|
|
31
|
+
return client.request(`/reputation/agent/${encodeURIComponent(agentDid)}/reputation`);
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
/**
|
|
33
|
-
* Get a specific credential
|
|
35
|
+
* Get a specific credential
|
|
36
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
37
|
+
* @param {string} credentialId
|
|
38
|
+
* @returns {Promise<Object>}
|
|
34
39
|
*/
|
|
35
40
|
export async function getCredential(client, credentialId) {
|
|
36
|
-
return client.
|
|
41
|
+
return client.request(`/reputation/credential/${credentialId}`);
|
|
37
42
|
}
|
|
38
43
|
|
|
39
44
|
/**
|
|
40
45
|
* Verify a credential
|
|
46
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
47
|
+
* @param {Object} credential - { credential_id: string }
|
|
48
|
+
* @returns {Promise<{valid: boolean, reason?: string}>}
|
|
41
49
|
*/
|
|
42
|
-
export async function verifyCredential(client,
|
|
43
|
-
return client.
|
|
50
|
+
export async function verifyCredential(client, credential) {
|
|
51
|
+
return client.request('/reputation/verify', {
|
|
52
|
+
method: 'POST',
|
|
53
|
+
body: JSON.stringify(credential),
|
|
54
|
+
});
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
/**
|
|
47
58
|
* Get the revocation list
|
|
59
|
+
* @param {import('./client.js').CoinPayClient} client
|
|
60
|
+
* @returns {Promise<Object>}
|
|
48
61
|
*/
|
|
49
62
|
export async function getRevocationList(client) {
|
|
50
|
-
return client.
|
|
63
|
+
return client.request('/reputation/revocation-list');
|
|
51
64
|
}
|