@relaycore/sdk 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/PUBLISHING.md +37 -0
- package/README.md +434 -0
- package/agent-sdk.ts +392 -0
- package/consumer-sdk.ts +434 -0
- package/dist/index.js +14116 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +14057 -0
- package/dist/index.mjs.map +1 -0
- package/hooks.ts +250 -0
- package/index.ts +153 -0
- package/lib/erc8004.ts +51 -0
- package/lib/facilitator.ts +65 -0
- package/lib/ipfs.ts +71 -0
- package/lib/supabase.ts +5 -0
- package/lib/x402.ts +220 -0
- package/package.json +38 -0
- package/provider-sdk.ts +311 -0
- package/relay-agent.ts +1414 -0
- package/relay-rwa.ts +128 -0
- package/relay-service.ts +886 -0
- package/tsconfig.json +23 -0
- package/tsup.config.ts +19 -0
- package/types/chat.types.ts +146 -0
- package/types/x402.types.ts +114 -0
package/PUBLISHING.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Publishing the Relay Core SDK
|
|
2
|
+
|
|
3
|
+
The SDK has been refactored to be self-contained and ready for the npm registry.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
1. You need an npm account.
|
|
7
|
+
2. You must belong to the `relaycore` organization on npm (or change the package name).
|
|
8
|
+
|
|
9
|
+
## Steps
|
|
10
|
+
|
|
11
|
+
1. **Login to npm**
|
|
12
|
+
```bash
|
|
13
|
+
npm login
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
2. **Build the SDK**
|
|
17
|
+
Ensure dependencies are installed and build:
|
|
18
|
+
```bash
|
|
19
|
+
cd src/sdk
|
|
20
|
+
npm install
|
|
21
|
+
npm run build
|
|
22
|
+
```
|
|
23
|
+
*Success means you see `dist/` folder with .js and .d.ts files.*
|
|
24
|
+
|
|
25
|
+
3. **Publish**
|
|
26
|
+
```bash
|
|
27
|
+
npm publish --access public
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Troubleshooting
|
|
31
|
+
- **"You do not have permission to publish"**:
|
|
32
|
+
- Check if you are logged in: `npm whoami`
|
|
33
|
+
- Check if you own `@relaycore`. If not, change `"name"` in `package.json` to `@<your-username>/relaycore-sdk`.
|
|
34
|
+
|
|
35
|
+
- **Build fails**:
|
|
36
|
+
- Ensure all dependencies are installed (`npm install`).
|
|
37
|
+
- Check `tsup.config.ts` if new native dependencies are added.
|
package/README.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# Relay Core SDK
|
|
2
|
+
|
|
3
|
+
TypeScript SDK for building AI agents and service providers on Relay Core. Provides agent discovery, x402 payment handling, session management, and service registration with production-grade error handling and observability.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @relaycore/sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Agent SDK
|
|
12
|
+
|
|
13
|
+
The Agent SDK enables autonomous agents to discover services, manage payment sessions, and execute paid operations.
|
|
14
|
+
|
|
15
|
+
### Basic Setup
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { RelayAgent, createAgent } from '@relaycore/sdk';
|
|
19
|
+
|
|
20
|
+
const agent = createAgent({
|
|
21
|
+
wallet: signer, // ethers.Signer from connected wallet
|
|
22
|
+
apiKey: "rc_test_...", // From Dashboard → API Keys
|
|
23
|
+
network: 'cronos-testnet',
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Service Discovery
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
const service = await agent.selectService({
|
|
31
|
+
category: 'data.prices',
|
|
32
|
+
constraints: {
|
|
33
|
+
minReputation: 90,
|
|
34
|
+
maxLatency: 200,
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Service Execution
|
|
40
|
+
|
|
41
|
+
```typescript
|
|
42
|
+
const result = await agent.execute(service, { pair: 'BTC/USD' });
|
|
43
|
+
|
|
44
|
+
if (result.success) {
|
|
45
|
+
console.log('Price:', result.data);
|
|
46
|
+
console.log('Latency:', result.metrics.totalMs, 'ms');
|
|
47
|
+
} else {
|
|
48
|
+
console.log('Error:', result.error?.message);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Session Management
|
|
53
|
+
|
|
54
|
+
**Create Session**
|
|
55
|
+
```typescript
|
|
56
|
+
const { sessionId, paymentRequest } = await agent.createSession({
|
|
57
|
+
maxSpend: 10, // USDC
|
|
58
|
+
durationHours: 24,
|
|
59
|
+
authorizedAgents: [] // Optional: restrict to specific agents
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
console.log(`Session ID: ${sessionId}`);
|
|
63
|
+
console.log(`Pay ${paymentRequest.amount} USDC to ${paymentRequest.payTo}`);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
**Activate Session**
|
|
67
|
+
```typescript
|
|
68
|
+
// After transferring USDC to paymentRequest.payTo
|
|
69
|
+
const activation = await agent.activateSession(
|
|
70
|
+
sessionId,
|
|
71
|
+
"0x...txHash...", // USDC transfer transaction hash
|
|
72
|
+
paymentRequest.amount
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
if (activation.success) {
|
|
76
|
+
console.log("Session activated");
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Query Session**
|
|
81
|
+
```typescript
|
|
82
|
+
const session = await agent.getSession(sessionId);
|
|
83
|
+
console.log(`Budget: ${session.maxSpend} USDC`);
|
|
84
|
+
console.log(`Spent: ${session.spent} USDC`);
|
|
85
|
+
console.log(`Remaining: ${Number(session.maxSpend) - Number(session.spent)} USDC`);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### Trust Policy
|
|
89
|
+
|
|
90
|
+
```typescript
|
|
91
|
+
agent.setTrustPolicy({
|
|
92
|
+
minReputation: 85,
|
|
93
|
+
maxLatency: 500,
|
|
94
|
+
verifiedOnly: true,
|
|
95
|
+
blacklistedProviders: ['0x...'],
|
|
96
|
+
});
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Workflow Execution
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const result = await agent.executeWorkflow([
|
|
103
|
+
{ name: 'getPrice', criteria: { category: 'data.prices' } },
|
|
104
|
+
{ name: 'validate', transform: (price) => price.value > 0 ? price : null },
|
|
105
|
+
{ name: 'trade', criteria: { category: 'trading.execution' } },
|
|
106
|
+
], { pair: 'BTC/USD' });
|
|
107
|
+
|
|
108
|
+
console.log('Steps completed:', result.completedSteps);
|
|
109
|
+
console.log('Total time:', result.totalMs, 'ms');
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### Outcome Tracking
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
agent.onOutcome((outcome) => {
|
|
116
|
+
console.log(`Service ${outcome.serviceId}: ${outcome.success ? 'success' : 'failure'}`);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
const stats = agent.memory.getStats();
|
|
120
|
+
console.log('Success rate:', stats.successRate);
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Agent Discovery
|
|
124
|
+
|
|
125
|
+
**Discover Single Agent**
|
|
126
|
+
```typescript
|
|
127
|
+
const card = await agent.discoverAgentCard('https://perpai.relaycore.xyz');
|
|
128
|
+
|
|
129
|
+
if (card) {
|
|
130
|
+
console.log('Agent:', card.name);
|
|
131
|
+
console.log('Capabilities:', card.capabilities);
|
|
132
|
+
|
|
133
|
+
card.resources.forEach(resource => {
|
|
134
|
+
console.log(`${resource.title}: ${resource.url}`);
|
|
135
|
+
console.log(` Price: ${resource.price}`);
|
|
136
|
+
console.log(` Settlement: ${resource.paywall.settlement}`);
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
**Discover Multiple Agents**
|
|
142
|
+
```typescript
|
|
143
|
+
const agents = await agent.discoverRemoteAgents([
|
|
144
|
+
'https://perpai.relaycore.xyz',
|
|
145
|
+
'https://rwa.relaycore.xyz',
|
|
146
|
+
'https://treasury.relaycore.xyz',
|
|
147
|
+
]);
|
|
148
|
+
|
|
149
|
+
const onlineAgents = agents.filter(a => a.online);
|
|
150
|
+
console.log(`${onlineAgents.length}/${agents.length} agents online`);
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Get Local Agent Card**
|
|
154
|
+
```typescript
|
|
155
|
+
const localCard = await agent.getAgentCard();
|
|
156
|
+
console.log('Local resources:', localCard.resources.length);
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Task Artifacts
|
|
160
|
+
|
|
161
|
+
**Create Task**
|
|
162
|
+
```typescript
|
|
163
|
+
const task = await agent.createTask({
|
|
164
|
+
service_id: 'perpai-quote',
|
|
165
|
+
inputs: { pair: 'BTC/USD', size: 1000 },
|
|
166
|
+
});
|
|
167
|
+
console.log('Task ID:', task.task_id);
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
**Settle Task**
|
|
171
|
+
```typescript
|
|
172
|
+
const result = await agent.execute(service, { pair: 'BTC/USD' });
|
|
173
|
+
|
|
174
|
+
if (result.success) {
|
|
175
|
+
await agent.settleTask(task.task_id, result.data, {
|
|
176
|
+
total_ms: result.metrics.totalMs,
|
|
177
|
+
payment_ms: result.metrics.paymentMs,
|
|
178
|
+
service_ms: result.metrics.serviceMs,
|
|
179
|
+
});
|
|
180
|
+
} else {
|
|
181
|
+
await agent.failTask(task.task_id, {
|
|
182
|
+
code: result.error?.code || 'UNKNOWN',
|
|
183
|
+
message: result.error?.message || 'Unknown error',
|
|
184
|
+
retryable: result.error?.retryable || false,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
**Query Tasks**
|
|
190
|
+
```typescript
|
|
191
|
+
const tasks = await agent.getTasks({
|
|
192
|
+
state: 'settled',
|
|
193
|
+
from: new Date(Date.now() - 24 * 60 * 60 * 1000), // Last 24 hours
|
|
194
|
+
limit: 50,
|
|
195
|
+
});
|
|
196
|
+
console.log('Completed tasks:', tasks.length);
|
|
197
|
+
|
|
198
|
+
const stats = await agent.getTaskStats();
|
|
199
|
+
console.log('Success rate:', (stats.success_rate * 100).toFixed(1) + '%');
|
|
200
|
+
console.log('Avg duration:', stats.avg_duration_ms + 'ms');
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Service SDK
|
|
204
|
+
|
|
205
|
+
The Service SDK enables service providers to register services, handle x402 payments, and record delivery proofs.
|
|
206
|
+
|
|
207
|
+
### Service Definition
|
|
208
|
+
|
|
209
|
+
```typescript
|
|
210
|
+
import { RelayService, createService, defineService, hashProof } from '@relaycore/sdk';
|
|
211
|
+
|
|
212
|
+
const myService = defineService({
|
|
213
|
+
name: 'price-feed',
|
|
214
|
+
category: 'data.prices',
|
|
215
|
+
price: '0.01', // USDC per call
|
|
216
|
+
inputType: 'PriceQuery',
|
|
217
|
+
outputType: 'PriceData',
|
|
218
|
+
tags: ['prices', 'real-time', 'crypto'],
|
|
219
|
+
});
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Service Registration
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
const provider = createService({
|
|
226
|
+
wallet: signer, // ethers.Signer
|
|
227
|
+
network: 'cronos-testnet',
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
const registered = await provider.register(myService);
|
|
231
|
+
console.log('Service ID:', registered.id);
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### Payment Handling
|
|
235
|
+
|
|
236
|
+
**Manual Payment Check**
|
|
237
|
+
```typescript
|
|
238
|
+
app.use('/api/price', async (req, res, next) => {
|
|
239
|
+
const paymentId = req.headers['x-payment-id'];
|
|
240
|
+
|
|
241
|
+
if (!paymentId) {
|
|
242
|
+
const requirements = await provider.createPaymentRequired({
|
|
243
|
+
amount: '0.01',
|
|
244
|
+
description: 'Price feed access',
|
|
245
|
+
});
|
|
246
|
+
return res.status(402).json(requirements);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
const { verified } = await provider.verifyPayment(paymentId);
|
|
250
|
+
if (!verified) {
|
|
251
|
+
return res.status(402).json({ error: 'Payment not verified' });
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
next();
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Delivery with Proof**
|
|
259
|
+
```typescript
|
|
260
|
+
app.get('/api/price', async (req, res) => {
|
|
261
|
+
const startTime = Date.now();
|
|
262
|
+
|
|
263
|
+
const result = { price: 42000.50, pair: 'BTC/USD', timestamp: Date.now() };
|
|
264
|
+
|
|
265
|
+
await provider.recordDelivery(req.headers['x-payment-id'], {
|
|
266
|
+
result,
|
|
267
|
+
proof: hashProof(result),
|
|
268
|
+
latencyMs: Date.now() - startTime,
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
res.json(result);
|
|
272
|
+
});
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Middleware Helper
|
|
276
|
+
|
|
277
|
+
```typescript
|
|
278
|
+
import { createPaymentMiddleware } from '@relaycore/sdk';
|
|
279
|
+
|
|
280
|
+
const paymentRequired = createPaymentMiddleware(provider, {
|
|
281
|
+
amount: '0.01',
|
|
282
|
+
description: 'API access',
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
app.use('/api/protected', paymentRequired, (req, res) => {
|
|
286
|
+
res.json({ data: 'protected data' });
|
|
287
|
+
});
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Payment Event Handlers
|
|
291
|
+
|
|
292
|
+
```typescript
|
|
293
|
+
provider.onPaymentReceived(async (ctx) => {
|
|
294
|
+
console.log('Payment received:', ctx.paymentId, ctx.amount, 'USDC');
|
|
295
|
+
|
|
296
|
+
const result = await processRequest(ctx.input);
|
|
297
|
+
|
|
298
|
+
ctx.deliver({
|
|
299
|
+
result,
|
|
300
|
+
proof: hashProof(result),
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
provider.onPaymentFailed(async (event) => {
|
|
305
|
+
console.log('Payment failed:', event.paymentId, event.error);
|
|
306
|
+
});
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Reputation and Metrics
|
|
310
|
+
|
|
311
|
+
**Check Reputation**
|
|
312
|
+
```typescript
|
|
313
|
+
const reputation = await provider.getReputation();
|
|
314
|
+
console.log('Score:', reputation.reputationScore);
|
|
315
|
+
console.log('Success rate:', reputation.successRate);
|
|
316
|
+
console.log('Trend:', reputation.trend);
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
**View Metrics**
|
|
320
|
+
```typescript
|
|
321
|
+
const metrics = await provider.getMetrics(serviceId, {
|
|
322
|
+
from: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000), // Last 7 days
|
|
323
|
+
interval: '1d',
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
metrics.forEach((m) => {
|
|
327
|
+
console.log(`${m.timestamp}: ${m.totalCalls} calls, ${m.successRate}% success`);
|
|
328
|
+
});
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
## x402 Protocol Implementation
|
|
332
|
+
|
|
333
|
+
### Protecting Routes
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
import { requireX402 } from '@relaycore/sdk';
|
|
337
|
+
|
|
338
|
+
router.get('/premium-data',
|
|
339
|
+
requireX402({
|
|
340
|
+
network: 'cronos-testnet',
|
|
341
|
+
payTo: '0xYourMerchantAddress',
|
|
342
|
+
asset: '0xUSDCAddress',
|
|
343
|
+
maxAmountRequired: '1000000', // 1 USDC
|
|
344
|
+
description: 'Access to premium data feed',
|
|
345
|
+
resource: '/api/premium-data',
|
|
346
|
+
}),
|
|
347
|
+
(req, res) => {
|
|
348
|
+
res.json({ data: 'Premium content' });
|
|
349
|
+
}
|
|
350
|
+
);
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
### Settlement Endpoint
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
import { handleX402Settlement, Facilitator } from '@relaycore/sdk';
|
|
357
|
+
|
|
358
|
+
router.post('/pay', async (req, res) => {
|
|
359
|
+
const { paymentId, paymentHeader, paymentRequirements } = req.body;
|
|
360
|
+
|
|
361
|
+
const facilitator = new Facilitator({ network: 'cronos-testnet' });
|
|
362
|
+
|
|
363
|
+
const result = await handleX402Settlement({
|
|
364
|
+
facilitator,
|
|
365
|
+
paymentId,
|
|
366
|
+
paymentHeader,
|
|
367
|
+
paymentRequirements,
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
if (!result.ok) {
|
|
371
|
+
return res.status(400).json(result);
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
res.json({ success: true, txHash: result.txHash });
|
|
375
|
+
});
|
|
376
|
+
```
|
|
377
|
+
|
|
378
|
+
### x402 Flow
|
|
379
|
+
|
|
380
|
+
1. Client requests protected resource
|
|
381
|
+
2. Server returns 402 Payment Required with payment requirements
|
|
382
|
+
3. Client creates EIP-3009 authorization
|
|
383
|
+
4. Client submits payment to settlement endpoint
|
|
384
|
+
5. Server verifies and settles via Facilitator
|
|
385
|
+
6. Client retries with x-payment-id header
|
|
386
|
+
7. Server returns protected content
|
|
387
|
+
|
|
388
|
+
## Error Handling
|
|
389
|
+
|
|
390
|
+
Both SDKs use structured errors for programmatic handling:
|
|
391
|
+
|
|
392
|
+
```typescript
|
|
393
|
+
const result = await agent.execute(service, input);
|
|
394
|
+
|
|
395
|
+
if (!result.success) {
|
|
396
|
+
switch (result.error?.code) {
|
|
397
|
+
case 'SERVICE_NOT_FOUND':
|
|
398
|
+
console.log('Service not found');
|
|
399
|
+
break;
|
|
400
|
+
case 'PAYMENT_FAILED':
|
|
401
|
+
console.log('Payment failed, check balance');
|
|
402
|
+
break;
|
|
403
|
+
case 'RATE_LIMITED':
|
|
404
|
+
await sleep(result.error.retryAfterMs);
|
|
405
|
+
// Retry
|
|
406
|
+
break;
|
|
407
|
+
case 'EXECUTION_TIMEOUT':
|
|
408
|
+
// Retry with longer timeout
|
|
409
|
+
break;
|
|
410
|
+
default:
|
|
411
|
+
console.log(result.error?.message);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
## Network Configuration
|
|
417
|
+
|
|
418
|
+
| Network | Chain ID | Description |
|
|
419
|
+
|---------|----------|-------------|
|
|
420
|
+
| `cronos-mainnet` | 25 | Cronos EVM Mainnet |
|
|
421
|
+
| `cronos-testnet` | 338 | Cronos EVM Testnet |
|
|
422
|
+
| `cronos-zkevm` | 388 | Cronos zkEVM Mainnet |
|
|
423
|
+
|
|
424
|
+
## Design Principles
|
|
425
|
+
|
|
426
|
+
1. **Progressive Configuration**: Start simple, add options as needed
|
|
427
|
+
2. **Explicit Payments**: No magic, full visibility into payment flow
|
|
428
|
+
3. **Proof of Delivery**: Every outcome has a hash for verification
|
|
429
|
+
4. **Structured Errors**: Retryable vs terminal, with explanations
|
|
430
|
+
5. **Built-in Observability**: Logs, metrics, and stats out of the box
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
MIT
|