Skip to content

Commit 42a439c

Browse files
committed
fix: rename reputation migration to avoid version collision
1 parent b337eaf commit 42a439c

File tree

24 files changed

+1980
-995
lines changed

24 files changed

+1980
-995
lines changed

packages/sdk/bin/coinpay.js

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,13 @@ ${colors.cyan}Commands:${colors.reset}
218218
events <id> Get escrow audit log
219219
auth <id> Authenticate with escrow token
220220
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+
221228
${colors.bright}webhook${colors.reset}
222229
logs <business-id> Get webhook logs
223230
test <business-id> Send test webhook
@@ -1577,6 +1584,156 @@ async function handleEscrow(subcommand, args, flags) {
15771584
}
15781585
}
15791586

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+
15801737
/**
15811738
* Main entry point
15821739
*/
@@ -1626,6 +1783,10 @@ async function main() {
16261783
case 'webhook':
16271784
await handleWebhook(subcommand, args, flags);
16281785
break;
1786+
1787+
case 'reputation':
1788+
await handleReputation(subcommand, args, flags);
1789+
break;
16291790

16301791
default:
16311792
print.error(`Unknown command: ${command}`);

packages/sdk/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@profullstack/coinpay",
3-
"version": "0.5.0",
3+
"version": "0.5.1",
44
"description": "CoinPay SDK & CLI — Accept cryptocurrency payments (BTC, ETH, SOL, POL, BCH, USDC) with wallet and swap support",
55
"type": "module",
66
"main": "./src/index.js",

packages/sdk/src/index.d.ts

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,10 @@ export {
105105
getRevocationList,
106106
} from './reputation.js';
107107
export type {
108-
TaskReceipt,
109-
ReputationSummary,
110-
MultiWindowReputation,
111-
CredentialVerification,
112-
RevocationList,
108+
ReceiptInput,
109+
ReputationWindow,
110+
ReputationResult,
111+
Credential,
113112
} from './reputation.js';
114113

115114
import { CoinPayClient } from './client.js';

packages/sdk/src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ import {
7878
} from './wallet.js';
7979

8080
// Swap exports
81+
// Reputation exports
8182
import {
8283
submitReceipt,
8384
getReputation,

packages/sdk/src/reputation.d.ts

Lines changed: 45 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,71 @@
11
import { CoinPayClient } from './client';
22

3-
export interface TaskReceipt {
3+
export interface ReceiptInput {
44
receipt_id: string;
55
task_id: string;
66
agent_did: string;
77
buyer_did: string;
8-
platform_did: string;
8+
platform_did?: string;
99
escrow_tx?: string;
10-
amount: number;
11-
currency: string;
10+
amount?: number;
11+
currency?: string;
1212
category?: string;
1313
sla?: Record<string, unknown>;
14-
outcome: 'completed' | 'failed' | 'disputed' | 'cancelled';
14+
outcome: 'accepted' | 'rejected' | 'disputed';
1515
dispute?: boolean;
1616
artifact_hash?: string;
1717
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;
2122
};
2223
finalized_at?: string;
2324
}
2425

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;
3430
total_volume: number;
35-
avg_task_value: number;
3631
unique_buyers: number;
32+
avg_task_value: number;
33+
accepted_rate: number;
34+
dispute_rate: number;
3735
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+
};
3845
anti_gaming: {
39-
circular_payment: boolean;
40-
burst_detected: boolean;
41-
below_economic_threshold: boolean;
42-
insufficient_unique_buyers: boolean;
4346
flagged: boolean;
44-
details: string[];
47+
flags: string[];
48+
adjusted_weight: number;
4549
};
4650
}
4751

48-
export interface MultiWindowReputation {
49-
'30d': ReputationSummary;
50-
'90d': ReputationSummary;
51-
all: ReputationSummary;
52-
}
53-
54-
export interface CredentialVerification {
55-
valid: boolean;
56-
reason: string;
57-
credential?: Record<string, unknown>;
58-
}
59-
60-
export interface RevocationList {
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;
6365
}
6466

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>;
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>> }>;

0 commit comments

Comments
 (0)