@profullstack/coinpay 0.5.0 → 0.5.2

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 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,214 @@ 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
+ case 'did': {
1731
+ const didSubcommand = args[0];
1732
+ const client = createClient();
1733
+
1734
+ if (didSubcommand === 'claim') {
1735
+ const { claimDid } = await import('../src/reputation.js');
1736
+ const result = await claimDid(client);
1737
+
1738
+ if (result.did) {
1739
+ print.success(`DID claimed: ${result.did}`);
1740
+ console.log(` Public Key: ${result.public_key}`);
1741
+ console.log(` Verified: ${result.verified}`);
1742
+ } else {
1743
+ print.error(result.error || 'Failed to claim DID');
1744
+ }
1745
+
1746
+ if (flags.json) print.json(result);
1747
+ } else if (didSubcommand === 'link') {
1748
+ const didValue = flags.did;
1749
+ const publicKey = flags['public-key'];
1750
+ const signature = flags.signature;
1751
+
1752
+ if (!didValue || !publicKey || !signature) {
1753
+ print.error('Required: --did <did> --public-key <key> --signature <sig>');
1754
+ print.info('Usage: coinpay reputation did link --did <did> --public-key <key> --signature <sig>');
1755
+ break;
1756
+ }
1757
+
1758
+ const { linkDid } = await import('../src/reputation.js');
1759
+ const result = await linkDid(client, { did: didValue, publicKey, signature });
1760
+
1761
+ if (result.did) {
1762
+ print.success(`DID linked: ${result.did}`);
1763
+ console.log(` Verified: ${result.verified}`);
1764
+ } else {
1765
+ print.error(result.error || 'Failed to link DID');
1766
+ }
1767
+
1768
+ if (flags.json) print.json(result);
1769
+ } else {
1770
+ // Default: show current DID
1771
+ const { getMyDid } = await import('../src/reputation.js');
1772
+ const result = await getMyDid(client);
1773
+
1774
+ if (result.did) {
1775
+ print.success(`Your DID: ${result.did}`);
1776
+ console.log(` Public Key: ${result.public_key}`);
1777
+ console.log(` Verified: ${result.verified}`);
1778
+ console.log(` Created: ${result.created_at}`);
1779
+ } else {
1780
+ print.info('No DID found. Run: coinpay reputation did claim');
1781
+ }
1782
+
1783
+ if (flags.json) print.json(result);
1784
+ }
1785
+ break;
1786
+ }
1787
+
1788
+ default:
1789
+ print.error(`Unknown reputation command: ${subcommand}`);
1790
+ print.info('Available: submit, query, credential, verify, revocations, did');
1791
+ process.exit(1);
1792
+ }
1793
+ }
1794
+
1580
1795
  /**
1581
1796
  * Main entry point
1582
1797
  */
@@ -1626,6 +1841,10 @@ async function main() {
1626
1841
  case 'webhook':
1627
1842
  await handleWebhook(subcommand, args, flags);
1628
1843
  break;
1844
+
1845
+ case 'reputation':
1846
+ await handleReputation(subcommand, args, flags);
1847
+ break;
1629
1848
 
1630
1849
  default:
1631
1850
  print.error(`Unknown command: ${command}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@profullstack/coinpay",
3
- "version": "0.5.0",
3
+ "version": "0.5.2",
4
4
  "description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet and swap support",
5
5
  "type": "module",
6
6
  "main": "./src/index.js",
package/src/index.d.ts CHANGED
@@ -105,11 +105,10 @@ export {
105
105
  getRevocationList,
106
106
  } from './reputation.js';
107
107
  export type {
108
- TaskReceipt,
109
- ReputationSummary,
110
- MultiWindowReputation,
111
- CredentialVerification,
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
@@ -78,6 +78,7 @@ import {
78
78
  } from './wallet.js';
79
79
 
80
80
  // Swap exports
81
+ // Reputation exports
81
82
  import {
82
83
  submitReceipt,
83
84
  getReputation,
@@ -1,69 +1,82 @@
1
1
  import { CoinPayClient } from './client';
2
2
 
3
- export interface TaskReceipt {
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: string;
8
+ platform_did?: string;
9
9
  escrow_tx?: string;
10
- amount: number;
11
- currency: string;
10
+ amount?: number;
11
+ currency?: string;
12
12
  category?: string;
13
13
  sla?: Record<string, unknown>;
14
- outcome: 'completed' | 'failed' | 'disputed' | 'cancelled';
14
+ outcome: 'accepted' | 'rejected' | 'disputed';
15
15
  dispute?: boolean;
16
16
  artifact_hash?: string;
17
17
  signatures: {
18
- agent?: string;
19
- buyer?: string;
20
- platform?: string;
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 ReputationSummary {
26
- agent_did: string;
27
- total_tasks: number;
28
- completed: number;
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
- details: string[];
47
+ flags: string[];
48
+ adjusted_weight: number;
45
49
  };
46
50
  }
47
51
 
48
- export interface MultiWindowReputation {
49
- '30d': ReputationSummary;
50
- '90d': ReputationSummary;
51
- all: ReputationSummary;
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;
52
65
  }
53
66
 
54
- export interface CredentialVerification {
55
- valid: boolean;
56
- reason: string;
57
- credential?: Record<string, unknown>;
58
- }
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>> }>;
59
72
 
60
- export interface RevocationList {
61
- revoked: string[];
62
- details: Array<{ credential_id: string; reason: string; revoked_at: string }>;
73
+ export interface DidInfo {
74
+ did: string;
75
+ public_key: string;
76
+ verified: boolean;
77
+ created_at: string;
63
78
  }
64
79
 
65
- export function submitReceipt(client: CoinPayClient, receipt: TaskReceipt): Promise<{ id: string; verified_signatures: string[] }>;
66
- export function getReputation(client: CoinPayClient, agentDid: string): Promise<MultiWindowReputation>;
67
- export function getCredential(client: CoinPayClient, credentialId: string): Promise<Record<string, unknown>>;
68
- export function verifyCredential(client: CoinPayClient, credentialId: string): Promise<CredentialVerification>;
69
- export function getRevocationList(client: CoinPayClient): Promise<RevocationList>;
80
+ export function getMyDid(client: CoinPayClient): Promise<DidInfo>;
81
+ export function claimDid(client: CoinPayClient): Promise<DidInfo>;
82
+ export function linkDid(client: CoinPayClient, params: { did: string; publicKey: string; signature: string }): Promise<DidInfo>;
package/src/reputation.js CHANGED
@@ -1,51 +1,104 @@
1
1
  /**
2
2
  * Reputation SDK Module
3
3
  *
4
- * Submit receipts, query reputation, verify credentials.
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
- * const client = new CoinPayClient({ apiKey: 'your-key' });
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._request('POST', '/api/reputation/receipt', receipt);
18
+ return client.request('/reputation/receipt', {
19
+ method: 'POST',
20
+ body: JSON.stringify(receipt),
21
+ });
22
22
  }
23
23
 
24
24
  /**
25
- * Get aggregated reputation for an agent DID
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
- const encoded = encodeURIComponent(agentDid);
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 by ID
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._request('GET', `/api/reputation/credential/${credentialId}`);
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, credentialId) {
43
- return client._request('POST', '/api/reputation/verify', { credential_id: credentialId });
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._request('GET', '/api/reputation/revocation-list');
63
+ return client.request('/reputation/revocation-list');
64
+ }
65
+
66
+ /**
67
+ * Get the authenticated merchant's DID
68
+ * @param {import('./client.js').CoinPayClient} client
69
+ * @returns {Promise<Object>}
70
+ */
71
+ export async function getMyDid(client) {
72
+ return client.request('/reputation/did/me');
73
+ }
74
+
75
+ /**
76
+ * Claim (auto-generate) a new DID for the authenticated merchant
77
+ * @param {import('./client.js').CoinPayClient} client
78
+ * @returns {Promise<Object>}
79
+ */
80
+ export async function claimDid(client) {
81
+ return client.request('/reputation/did/claim', {
82
+ method: 'POST',
83
+ });
84
+ }
85
+
86
+ /**
87
+ * Link an existing DID to the authenticated merchant
88
+ * @param {import('./client.js').CoinPayClient} client
89
+ * @param {Object} params
90
+ * @param {string} params.did - The DID to link
91
+ * @param {string} params.publicKey - Base64url-encoded public key
92
+ * @param {string} params.signature - Base64url-encoded signature
93
+ * @returns {Promise<Object>}
94
+ */
95
+ export async function linkDid(client, { did, publicKey, signature }) {
96
+ return client.request('/reputation/did/claim', {
97
+ method: 'POST',
98
+ body: JSON.stringify({
99
+ did,
100
+ public_key: publicKey,
101
+ signature,
102
+ }),
103
+ });
51
104
  }