x402-engineer 0.1.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.
Files changed (38) hide show
  1. package/AGENT.md +102 -0
  2. package/README.md +43 -0
  3. package/dist/cli.cjs +137 -0
  4. package/package.json +51 -0
  5. package/skills/stellar-dev/SKILL.md +146 -0
  6. package/skills/stellar-dev/advanced-patterns.md +188 -0
  7. package/skills/stellar-dev/api-rpc-horizon.md +521 -0
  8. package/skills/stellar-dev/common-pitfalls.md +510 -0
  9. package/skills/stellar-dev/contracts-soroban.md +565 -0
  10. package/skills/stellar-dev/ecosystem.md +430 -0
  11. package/skills/stellar-dev/frontend-stellar-sdk.md +651 -0
  12. package/skills/stellar-dev/resources.md +306 -0
  13. package/skills/stellar-dev/security.md +491 -0
  14. package/skills/stellar-dev/standards-reference.md +94 -0
  15. package/skills/stellar-dev/stellar-assets.md +419 -0
  16. package/skills/stellar-dev/testing.md +786 -0
  17. package/skills/stellar-dev/zk-proofs.md +136 -0
  18. package/skills/x402-add-paywall/SKILL.md +208 -0
  19. package/skills/x402-add-paywall/references/patterns.md +132 -0
  20. package/skills/x402-debug/SKILL.md +92 -0
  21. package/skills/x402-debug/references/checklist.md +146 -0
  22. package/skills/x402-explain/SKILL.md +136 -0
  23. package/skills/x402-init/SKILL.md +129 -0
  24. package/skills/x402-init/templates/env-example.md +17 -0
  25. package/skills/x402-init/templates/express/config.ts.md +29 -0
  26. package/skills/x402-init/templates/express/server.ts.md +30 -0
  27. package/skills/x402-init/templates/fastify/adapter.ts.md +66 -0
  28. package/skills/x402-init/templates/fastify/config.ts.md +29 -0
  29. package/skills/x402-init/templates/fastify/server.ts.md +90 -0
  30. package/skills/x402-init/templates/hono/config.ts.md +29 -0
  31. package/skills/x402-init/templates/hono/server.ts.md +31 -0
  32. package/skills/x402-init/templates/next-app-router/config.ts.md +29 -0
  33. package/skills/x402-init/templates/next-app-router/server.ts.md +31 -0
  34. package/skills/x402-stellar/SKILL.md +139 -0
  35. package/skills/x402-stellar/references/api.md +237 -0
  36. package/skills/x402-stellar/references/patterns.md +276 -0
  37. package/skills/x402-stellar/references/setup.md +138 -0
  38. package/skills/x402-stellar/scripts/check-deps.js +218 -0
@@ -0,0 +1,521 @@
1
+ # API Access (Stellar RPC + Horizon)
2
+
3
+ ## Overview
4
+
5
+ Stellar provides two API paradigms:
6
+
7
+ | API | Status | Use Case |
8
+ |-----|--------|----------|
9
+ | **Stellar RPC** | Preferred | Soroban, real-time state, new projects |
10
+ | **Horizon** | Legacy-focused | Historical data, legacy applications |
11
+
12
+ **Recommendation**: Use Stellar RPC for all new projects. Use Horizon mainly for historical queries and legacy compatibility paths.
13
+
14
+ ## Quick Navigation
15
+ - RPC methods and usage: [Stellar RPC](#stellar-rpc)
16
+ - Horizon endpoints and streaming: [Horizon API (Legacy)](#horizon-api-legacy)
17
+ - Migration strategy: [Migration: Horizon to RPC](#migration-horizon-to-rpc)
18
+ - Data history/indexing options: [Historical Data Access](#historical-data-access)
19
+ - Environment setup and endpoints: [Network Configuration](#network-configuration)
20
+
21
+ ## Stellar RPC
22
+
23
+ ### Endpoints
24
+
25
+ > Note: SDF directly provides Futurenet public RPC. For Mainnet RPC, select a provider from the [RPC providers directory](https://developers.stellar.org/docs/data/apis/rpc/providers).
26
+
27
+ | Network | RPC URL |
28
+ |---------|---------|
29
+ | Mainnet | Provider-specific endpoint (see [RPC providers directory](https://developers.stellar.org/docs/data/apis/rpc/providers)) |
30
+ | Testnet | `https://soroban-testnet.stellar.org` |
31
+ | Futurenet | `https://rpc-futurenet.stellar.org` |
32
+ | Local | `http://localhost:8000/soroban/rpc` |
33
+
34
+ ### Setup
35
+
36
+ ```typescript
37
+ import * as StellarSdk from "@stellar/stellar-sdk";
38
+
39
+ const rpc = new StellarSdk.rpc.Server("https://soroban-testnet.stellar.org");
40
+ ```
41
+
42
+ ### Key Methods
43
+
44
+ #### Get Account
45
+
46
+ ```typescript
47
+ const account = await rpc.getAccount(publicKey);
48
+ // Returns account with sequence number for transaction building
49
+ ```
50
+
51
+ #### Get Health
52
+
53
+ ```typescript
54
+ const health = await rpc.getHealth();
55
+ // { status: "healthy" }
56
+ ```
57
+
58
+ #### Get Latest Ledger
59
+
60
+ ```typescript
61
+ const ledger = await rpc.getLatestLedger();
62
+ // { id: "...", sequence: 123456, protocolVersion: 25 }
63
+ ```
64
+
65
+ #### Get Ledger Entries
66
+
67
+ ```typescript
68
+ // Read contract storage
69
+ const key = StellarSdk.xdr.LedgerKey.contractData(
70
+ new StellarSdk.xdr.LedgerKeyContractData({
71
+ contract: new StellarSdk.Address(contractId).toScAddress(),
72
+ key: StellarSdk.xdr.ScVal.scvSymbol("Counter"),
73
+ durability: StellarSdk.xdr.ContractDataDurability.persistent(),
74
+ })
75
+ );
76
+
77
+ const entries = await rpc.getLedgerEntries(key);
78
+ if (entries.entries.length > 0) {
79
+ const value = StellarSdk.scValToNative(
80
+ entries.entries[0].val.contractData().val()
81
+ );
82
+ }
83
+ ```
84
+
85
+ #### Simulate Transaction
86
+
87
+ ```typescript
88
+ const simulation = await rpc.simulateTransaction(transaction);
89
+
90
+ if (StellarSdk.rpc.Api.isSimulationError(simulation)) {
91
+ console.error("Simulation failed:", simulation.error);
92
+ } else if (StellarSdk.rpc.Api.isSimulationSuccess(simulation)) {
93
+ console.log("Cost:", simulation.cost);
94
+ console.log("Result:", simulation.result);
95
+ }
96
+ ```
97
+
98
+ #### Send Transaction
99
+
100
+ ```typescript
101
+ const response = await rpc.sendTransaction(signedTransaction);
102
+
103
+ if (response.status === "PENDING") {
104
+ // Poll for result
105
+ let result = await rpc.getTransaction(response.hash);
106
+ while (result.status === "NOT_FOUND") {
107
+ await new Promise(r => setTimeout(r, 1000));
108
+ result = await rpc.getTransaction(response.hash);
109
+ }
110
+
111
+ if (result.status === "SUCCESS") {
112
+ console.log("Success:", result.returnValue);
113
+ } else {
114
+ console.error("Failed:", result.status);
115
+ }
116
+ }
117
+ ```
118
+
119
+ #### Get Transaction
120
+
121
+ ```typescript
122
+ const tx = await rpc.getTransaction(txHash);
123
+ // status: "SUCCESS" | "FAILED" | "NOT_FOUND"
124
+ // returnValue: ScVal (for contract calls)
125
+ // ledger: number
126
+ ```
127
+
128
+ #### Get Events
129
+
130
+ ```typescript
131
+ const events = await rpc.getEvents({
132
+ startLedger: 1000000,
133
+ filters: [
134
+ {
135
+ type: "contract",
136
+ contractIds: [contractId],
137
+ topics: [
138
+ ["*", StellarSdk.xdr.ScVal.scvSymbol("transfer").toXDR("base64")],
139
+ ],
140
+ },
141
+ ],
142
+ });
143
+
144
+ for (const event of events.events) {
145
+ console.log("Event:", event.topic, event.value);
146
+ }
147
+ ```
148
+
149
+ ### RPC Limitations
150
+
151
+ - **7-day history for most methods**: `getTransaction`, `getEvents`, etc. only cover recent data
152
+ - **`getLedgers` exception**: "Infinite Scroll" feature queries any ledger back to genesis via the data lake
153
+ - **No streaming**: Poll for updates (no WebSocket)
154
+ - **Contract-focused**: Limited classic Stellar data
155
+
156
+ ## Horizon API (Legacy)
157
+
158
+ ### Endpoints
159
+
160
+ | Network | Horizon URL |
161
+ |---------|-------------|
162
+ | Mainnet | `https://horizon.stellar.org` |
163
+ | Testnet | `https://horizon-testnet.stellar.org` |
164
+ | Local | `http://localhost:8000` |
165
+
166
+ ### Setup
167
+
168
+ ```typescript
169
+ import * as StellarSdk from "@stellar/stellar-sdk";
170
+
171
+ const server = new StellarSdk.Horizon.Server("https://horizon-testnet.stellar.org");
172
+ ```
173
+
174
+ ### Common Operations
175
+
176
+ #### Load Account
177
+
178
+ ```typescript
179
+ const account = await server.loadAccount(publicKey);
180
+ // Full account details including balances, signers, data
181
+ ```
182
+
183
+ #### Get Account Balances
184
+
185
+ ```typescript
186
+ const account = await server.loadAccount(publicKey);
187
+ for (const balance of account.balances) {
188
+ if (balance.asset_type === "native") {
189
+ console.log("XLM:", balance.balance);
190
+ } else {
191
+ console.log(`${balance.asset_code}:`, balance.balance);
192
+ }
193
+ }
194
+ ```
195
+
196
+ #### Get Transactions
197
+
198
+ ```typescript
199
+ // Account transactions
200
+ const transactions = await server
201
+ .transactions()
202
+ .forAccount(publicKey)
203
+ .order("desc")
204
+ .limit(10)
205
+ .call();
206
+
207
+ // Specific transaction
208
+ const tx = await server
209
+ .transactions()
210
+ .transaction(txHash)
211
+ .call();
212
+ ```
213
+
214
+ #### Get Operations
215
+
216
+ ```typescript
217
+ const operations = await server
218
+ .operations()
219
+ .forAccount(publicKey)
220
+ .order("desc")
221
+ .limit(20)
222
+ .call();
223
+
224
+ for (const op of operations.records) {
225
+ console.log(op.type, op.created_at);
226
+ }
227
+ ```
228
+
229
+ #### Get Payments
230
+
231
+ ```typescript
232
+ const payments = await server
233
+ .payments()
234
+ .forAccount(publicKey)
235
+ .order("desc")
236
+ .call();
237
+
238
+ for (const payment of payments.records) {
239
+ if (payment.type === "payment") {
240
+ console.log(
241
+ `${payment.from} -> ${payment.to}: ${payment.amount} ${payment.asset_code || "XLM"}`
242
+ );
243
+ }
244
+ }
245
+ ```
246
+
247
+ #### Get Effects
248
+
249
+ ```typescript
250
+ const effects = await server
251
+ .effects()
252
+ .forAccount(publicKey)
253
+ .limit(50)
254
+ .call();
255
+ ```
256
+
257
+ #### Streaming (Server-Sent Events)
258
+
259
+ ```typescript
260
+ // Stream transactions
261
+ const closeHandler = server
262
+ .transactions()
263
+ .forAccount(publicKey)
264
+ .cursor("now")
265
+ .stream({
266
+ onmessage: (tx) => {
267
+ console.log("New transaction:", tx.hash);
268
+ },
269
+ onerror: (error) => {
270
+ console.error("Stream error:", error);
271
+ },
272
+ });
273
+
274
+ // Close stream when done
275
+ closeHandler();
276
+ ```
277
+
278
+ #### Submit Transaction
279
+
280
+ ```typescript
281
+ try {
282
+ const result = await server.submitTransaction(signedTransaction);
283
+ console.log("Success:", result.hash);
284
+ } catch (error) {
285
+ if (error.response?.data?.extras?.result_codes) {
286
+ console.error("Error codes:", error.response.data.extras.result_codes);
287
+ }
288
+ }
289
+ ```
290
+
291
+ ### Pagination
292
+
293
+ ```typescript
294
+ // First page
295
+ let page = await server.transactions().forAccount(publicKey).limit(10).call();
296
+
297
+ // Next page
298
+ if (page.records.length > 0) {
299
+ page = await page.next();
300
+ }
301
+
302
+ // Previous page
303
+ page = await page.prev();
304
+ ```
305
+
306
+ ## Migration: Horizon to RPC
307
+
308
+ ### Account Loading
309
+
310
+ ```typescript
311
+ // Horizon (old)
312
+ const account = await horizonServer.loadAccount(publicKey);
313
+
314
+ // RPC (new)
315
+ const account = await rpc.getAccount(publicKey);
316
+ // Note: RPC returns less data, just what's needed for transactions
317
+ ```
318
+
319
+ ### Transaction Submission
320
+
321
+ ```typescript
322
+ // Horizon (for classic transactions)
323
+ const result = await horizonServer.submitTransaction(tx);
324
+
325
+ // RPC (for Soroban transactions)
326
+ const response = await rpc.sendTransaction(tx);
327
+ const result = await pollForResult(response.hash);
328
+ ```
329
+
330
+ ### Historical Data
331
+
332
+ ```typescript
333
+ // Horizon - full history
334
+ const allTxs = await horizonServer
335
+ .transactions()
336
+ .forAccount(publicKey)
337
+ .call();
338
+
339
+ // RPC - most methods limited to 7 days
340
+ // Exception: getLedgers can query back to genesis (Infinite Scroll)
341
+ // For full historical data, use:
342
+ // 1. Hubble (SDF's BigQuery dataset)
343
+ // 2. Galexie (data pipeline)
344
+ // 3. Your own indexer
345
+ ```
346
+
347
+ ### Streaming Replacement
348
+
349
+ ```typescript
350
+ // Horizon - native streaming
351
+ server.payments().stream({ onmessage: handlePayment });
352
+
353
+ // RPC - polling (no native streaming)
354
+ async function pollForUpdates() {
355
+ const lastLedger = await rpc.getLatestLedger();
356
+ // Check for new events/transactions
357
+ // Repeat on interval
358
+ }
359
+ setInterval(pollForUpdates, 5000);
360
+ ```
361
+
362
+ ## Historical Data Access
363
+
364
+ For data older than 7 days (not available via most RPC methods; `getLedgers` can reach genesis via Infinite Scroll):
365
+
366
+ ### Hubble (BigQuery)
367
+
368
+ ```sql
369
+ -- Query Stellar data in BigQuery
370
+ SELECT *
371
+ FROM `crypto-stellar.crypto_stellar.history_transactions`
372
+ WHERE source_account = 'G...'
373
+ ORDER BY created_at DESC
374
+ LIMIT 100
375
+ ```
376
+
377
+ ### Galexie
378
+
379
+ Self-hosted data pipeline for processing Stellar ledger data:
380
+ - https://github.com/stellar/galexie
381
+
382
+ ### Data Lake
383
+
384
+ RPC "Infinite Scroll" is powered by the Stellar data lake — a cloud-based object store (SEP-0054 format):
385
+ - **Public access**: `s3://aws-public-blockchain/v1.1/stellar/ledgers/pubnet` (AWS Open Data)
386
+ - **Self-host**: Use Galexie to export to AWS S3 or Google Cloud Storage
387
+ - **Hosted**: [Quasar (Lightsail Network)](https://quasar.lightsail.network) provides hosted Galexie Data Lake + Archive RPC endpoints
388
+ - **Size**: ~3.8TB, growing ~0.5TB/year
389
+ - **Cost**: ~$160/month self-hosted ($60 compute + $100 storage)
390
+ - **Docs**: https://developers.stellar.org/docs/data/apis/rpc/admin-guide/data-lake-integration
391
+
392
+ ### Third-Party Indexers
393
+
394
+ For complex queries, event streaming, or custom data pipelines beyond what RPC/Horizon provide:
395
+
396
+ - **Mercury** — Stellar-native indexer with Retroshades, GraphQL API (https://mercurydata.app)
397
+ - **SubQuery** — Multi-chain indexer with Stellar/Soroban support, event handlers (https://subquery.network)
398
+ - **Goldsky** — Real-time data replication pipelines and subgraphs (https://goldsky.com)
399
+ - **StellarExpert API** — Free, no-auth REST API for assets, accounts, ledger resolution (https://stellar.expert/openapi.html)
400
+
401
+ See the full indexer directory: https://developers.stellar.org/docs/data/indexers
402
+
403
+ ## Network Configuration
404
+
405
+ > For a React/Next.js-specific setup, see [frontend-stellar-sdk.md](frontend-stellar-sdk.md).
406
+ > For mainnet RPC, set `STELLAR_MAINNET_RPC_URL` from a provider in the [RPC providers directory](https://developers.stellar.org/docs/data/apis/rpc/providers).
407
+
408
+ ### Environment-Based Setup
409
+
410
+ ```typescript
411
+ // lib/stellar-config.ts
412
+ import * as StellarSdk from "@stellar/stellar-sdk";
413
+
414
+ type NetworkConfig = {
415
+ rpcUrl: string;
416
+ horizonUrl: string;
417
+ networkPassphrase: string;
418
+ friendbotUrl: string | null;
419
+ };
420
+
421
+ const requireEnv = (name: string): string => {
422
+ const value = process.env[name];
423
+ if (!value) throw new Error(`Missing required env var: ${name}`);
424
+ return value;
425
+ };
426
+
427
+ const configs: Record<string, NetworkConfig> = {
428
+ mainnet: {
429
+ rpcUrl: requireEnv("STELLAR_MAINNET_RPC_URL"),
430
+ horizonUrl: "https://horizon.stellar.org",
431
+ networkPassphrase: StellarSdk.Networks.PUBLIC,
432
+ friendbotUrl: null,
433
+ },
434
+ testnet: {
435
+ rpcUrl: "https://soroban-testnet.stellar.org",
436
+ horizonUrl: "https://horizon-testnet.stellar.org",
437
+ networkPassphrase: StellarSdk.Networks.TESTNET,
438
+ friendbotUrl: "https://friendbot.stellar.org",
439
+ },
440
+ local: {
441
+ rpcUrl: "http://localhost:8000/soroban/rpc",
442
+ horizonUrl: "http://localhost:8000",
443
+ networkPassphrase: "Standalone Network ; February 2017",
444
+ friendbotUrl: "http://localhost:8000/friendbot",
445
+ },
446
+ };
447
+
448
+ const network = process.env.STELLAR_NETWORK || "testnet";
449
+ export const config = configs[network];
450
+
451
+ export const rpc = new StellarSdk.rpc.Server(config.rpcUrl);
452
+ export const horizon = new StellarSdk.Horizon.Server(config.horizonUrl);
453
+ ```
454
+
455
+ ## Best Practices
456
+
457
+ ### Use RPC for:
458
+ - New application development
459
+ - Soroban contract interactions
460
+ - Transaction simulation and submission
461
+ - Real-time account state
462
+
463
+ ### Use Horizon for:
464
+ - Historical transaction queries
465
+ - Payment streaming
466
+ - Legacy application maintenance
467
+ - Rich account metadata
468
+
469
+ ### Error Handling
470
+
471
+ ```typescript
472
+ // RPC errors
473
+ try {
474
+ const result = await rpc.sendTransaction(tx);
475
+ } catch (error) {
476
+ if (error.code === 400) {
477
+ // Invalid transaction
478
+ } else if (error.code === 503) {
479
+ // Service unavailable
480
+ }
481
+ }
482
+
483
+ // Horizon errors
484
+ try {
485
+ const result = await horizon.submitTransaction(tx);
486
+ } catch (error) {
487
+ const extras = error.response?.data?.extras;
488
+ if (extras?.result_codes) {
489
+ // Detailed error codes
490
+ console.log("Transaction:", extras.result_codes.transaction);
491
+ console.log("Operations:", extras.result_codes.operations);
492
+ }
493
+ }
494
+ ```
495
+
496
+ ### Rate Limiting
497
+
498
+ Both RPC and Horizon have rate limits:
499
+ - Use exponential backoff for retries
500
+ - Cache responses where appropriate
501
+ - Consider running your own nodes for high-volume applications
502
+
503
+ ```typescript
504
+ async function withRetry<T>(fn: () => Promise<T>, maxRetries = 3): Promise<T> {
505
+ let lastError: Error;
506
+ for (let i = 0; i < maxRetries; i++) {
507
+ try {
508
+ return await fn();
509
+ } catch (error) {
510
+ lastError = error;
511
+ if (error.response?.status === 429) {
512
+ // Rate limited - exponential backoff
513
+ await new Promise(r => setTimeout(r, Math.pow(2, i) * 1000));
514
+ } else {
515
+ throw error;
516
+ }
517
+ }
518
+ }
519
+ throw lastError;
520
+ }
521
+ ```