diff --git a/sdk/README.md b/sdk/README.md
index 2defb7c..783c869 100644
--- a/sdk/README.md
+++ b/sdk/README.md
@@ -1,45 +1,109 @@
-# StellarKit Client SDK
+# StellarKit JavaScript Client
-A lightweight Node.js client that wraps all StellarKit API endpoints into clean async functions. Uses native `fetch` — no extra dependencies.
+A lightweight, class-based JavaScript client for the StellarKit API. Integrate Stellar blockchain data into your apps without writing raw fetch calls.
## Installation
-Copy `stellarkit-client.js` into your project, or require it directly:
+Download `stellarkit-client.js` and include it in your project:
-```js
-const { StellarKitClient, StellarKitError } = require("./stellarkit-client");
+```javascript
+const StellarKitClient = require('./sdk/stellarkit-client');
```
-## Usage
+For browser usage:
+```html
+
+```
-```js
-const { StellarKitClient, StellarKitError } = require("./stellarkit-client");
+## Getting Started
+Initialize the client with your API base URL and an optional API key.
+
+```javascript
const client = new StellarKitClient({
- baseUrl: "http://localhost:3000",
- apiKey: "optional-api-key", // omit if not using API key auth
+ baseUrl: 'http://localhost:3000', // or your production URL
+ apiKey: 'your-api-key' // optional
});
+```
+
+## Usage Examples
-// Each method returns a Promise resolving to the `data` field of the response
-const health = await client.getHealth();
-console.log(health.status); // "ok"
-
-// Errors throw StellarKitError with .status and .message
-try {
- const account = await client.getAccount("INVALID_KEY");
-} catch (err) {
- if (err instanceof StellarKitError) {
- console.error(err.status, err.message);
- }
+### Network & Fees
+
+```javascript
+// Get current network status
+const status = await client.getNetworkStatus();
+console.log(`Latest Ledger: ${status.latestLedger.sequence}`);
+
+// Get recommended fees for a transaction with 3 operations
+const fees = await client.getFeeEstimate(3);
+console.log(`Recommended Standard Fee: ${fees.totalFee.standard.stroops} stroops`);
+
+// Check if there is a fee surge
+const surge = await client.getFeeSurgeStatus();
+if (surge.isSurging) {
+ console.log('Warning: Fee surge in progress');
}
```
-## API
+### Account Details
-### Constructor
+```javascript
+const accountId = 'GAAZI4TCR3TY5OJHCTJC2A4QSY6CJWJH5IAJTGKIN2ER7LBNVKOCCWN';
-```js
-new StellarKitClient({ baseUrl, apiKey? })
+// Get full account info
+const account = await client.getAccount(accountId);
+console.log(`XLM Balance: ${account.xlm.balance}`);
+
+// Get account age and activity
+const inactivity = await client.getAccountInactivity(accountId);
+console.log(`Account status: ${inactivity.status}`);
+
+// Check if account can receive USDC
+const canReceive = await client.getAccountCanReceive(
+ accountId,
+ 'USDC',
+ 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN'
+);
+if (!canReceive.canReceive) {
+ console.log(`Reason: ${canReceive.reasons.join(', ')}`);
+}
+```
+
+### Assets & DEX
+
+```javascript
+// Get asset statistics
+const asset = await client.getAsset('USDC', 'GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN');
+console.log(`Total Supply: ${asset.amount}`);
+
+// Calculate DEX spread for XLM/USDC
+const spread = await client.getDexSpread(
+ 'XLM:native',
+ 'USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN'
+);
+console.log(`Bid-Ask Spread: ${spread.spreadPercent}%`);
+
+// Find effective exchange rate for 100 XLM to USDC
+const price = await client.getDexPrice(
+ 'XLM:native',
+ 'USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN',
+ 100
+);
+console.log(`You will receive: ${price.buyAmount} USDC`);
+```
+
+### Utilities
+
+```javascript
+// Validate a public key locally
+const validation = await client.validateAccount('GAAZI4...');
+if (!validation.isValid) {
+ console.error(`Invalid key: ${validation.reason}`);
+}
+
+// Fund a testnet account
+await client.fundAccount('GAAZI4...');
```
| Option | Type | Required | Description |
@@ -89,3 +153,34 @@ err.status // HTTP status code (e.g. 404)
err.message // Human-readable error message from the API
err.name // "StellarKitError"
```
+
+## Methods Reference
+
+Every endpoint in the StellarKit API has a corresponding method. All methods return a `Promise` that resolves to the `data` field of the API response.
+
+| Category | Method | Description |
+| --- | --- | --- |
+| **Network** | `getNetworkStatus()` | Latest ledger, fees, and protocol info |
+| | `getNetworkLedgerTiming()` | Analyze network ledger close time consistency |
+| **Fees** | `getFeeEstimate(ops)` | Fee tiers for transaction submission |
+| | `getFeeSurgeStatus()` | Identify current fee surge periods |
+| | `getFeeTrends()` | Analyze fee trends across last 50 ledgers |
+| **Account** | `getAccount(id)` | Full account details, balances, signers |
+| | `getAccountBalances(id)` | Native XLM and asset balances |
+| | `getAccountSequence(id)` | Current sequence number |
+| | `getAccountInactivity(id)` | Detect account inactivity (dormancy) |
+| | `getAccountCanReceive(id, code, issuer)` | Check if account can receive an asset |
+| | `getAccountSummary(id)` | Consolidated account, tx, and offer summary |
+| | `getAccountTrustlines(id)` | Trustlines with resolved TOML metadata |
+| | `getAccountPoolPositions(id)` | Share values in all liquidity pools |
+| | `searchAccountTransactions(id, memo)` | Search transactions by memo content |
+| **DEX** | `getDexSpread(sell, buy)` | Calculate bid-ask spread for a pair |
+| | `getDexPrice(sell, buy, amt)` | Best effective exchange rate |
+| | `getDexDepth(sell, buy)` | Full order book depth analysis |
+| **Liquidity Pools** | `getPoolProfitability(id)` | Annualized fee income estimate |
+| | `getPoolReserveRatio(id)` | Current reserve ratio and drift |
+| **Utils** | `fundAccount(id)` | Fund testnet account via Friendbot |
+| | `validateAccount(id)` | Validate public key format locally |
+| | `decodeXdr(xdr)` | Decode transaction XDR to JSON |
+
+... and many more. See `sdk/stellarkit-client.js` for the full list and JSDoc documentation.
diff --git a/sdk/stellarkit-client.js b/sdk/stellarkit-client.js
index a12a060..441c905 100644
--- a/sdk/stellarkit-client.js
+++ b/sdk/stellarkit-client.js
@@ -1,104 +1,770 @@
-"use strict";
-
+/**
+ * Custom error class for StellarKit API errors.
+ */
class StellarKitError extends Error {
- constructor(status, message) {
+ /**
+ * @param {string} message - Error message
+ * @param {number} status - HTTP status code
+ * @param {string} type - Error type from API
+ */
+ constructor(message, status, type) {
super(message);
this.name = "StellarKitError";
this.status = status;
+ this.type = type;
}
}
+/**
+ * StellarKit API Client for JavaScript
+ *
+ * A lightweight wrapper for the StellarKit API endpoints.
+ */
class StellarKitClient {
/**
- * @param {object} options
- * @param {string} options.baseUrl - Base URL of the StellarKit API (e.g. "http://localhost:3000")
- * @param {string} [options.apiKey] - Optional API key sent as X-API-Key header
+ * Create a new StellarKit API client.
+ *
+ * @param {Object} options - Configuration options
+ * @param {string} options.baseUrl - The base URL of the StellarKit API (e.g. 'https://api.stellarkit.io')
+ * @param {string} [options.apiKey] - Optional API key for authentication
*/
- constructor({ baseUrl, apiKey } = {}) {
- if (!baseUrl) throw new Error("baseUrl is required");
+ constructor({ baseUrl, apiKey }) {
+ if (!baseUrl) {
+ throw new Error("baseUrl is required");
+ }
this.baseUrl = baseUrl.replace(/\/$/, "");
- this.apiKey = apiKey || null;
+ this.apiKey = apiKey;
}
- async _request(path) {
- const headers = { "Content-Type": "application/json" };
- if (this.apiKey) headers["X-API-Key"] = this.apiKey;
+ /**
+ * Helper to make authorized requests to the API.
+ *
+ * @private
+ * @param {string} path - API endpoint path
+ * @param {Object} [options] - Request options
+ * @param {string} [options.method='GET'] - HTTP method
+ * @param {Object} [options.params] - Query parameters
+ * @param {Object} [options.body] - Request body
+ * @returns {Promise} The 'data' field of the API response
+ * @throws {StellarKitError} If the request fails or returns a non-200 response
+ */
+ async _request(path, { method = "GET", params = null, body = null } = {}) {
+ let urlString = `${this.baseUrl}${path}`;
+
+ if (params) {
+ const url = new URL(urlString, "http://dummy.com"); // Need a base for URL constructor
+ Object.keys(params).forEach(key => {
+ if (params[key] !== undefined && params[key] !== null) {
+ url.searchParams.append(key, params[key]);
+ }
+ });
+ urlString = urlString.includes("?")
+ ? `${urlString}&${url.searchParams.toString()}`
+ : `${this.baseUrl}${path}?${url.searchParams.toString()}`;
+ }
- const res = await fetch(`${this.baseUrl}${path}`, { headers });
- const json = await res.json();
+ const headers = {
+ "Content-Type": "application/json",
+ "Accept": "application/json",
+ };
- if (!res.ok) {
- const message = json?.error?.message || res.statusText;
- throw new StellarKitError(res.status, message);
+ if (this.apiKey) {
+ headers["x-api-key"] = this.apiKey;
}
- return json.data;
- }
+ const response = await fetch(urlString, {
+ method,
+ headers,
+ body: body ? JSON.stringify(body) : null,
+ });
- // ── Health & Network ────────────────────────────────────────────────────────
+ const result = await response.json();
- getHealth() {
+ if (!response.ok) {
+ throw new StellarKitError(
+ result.error?.message || response.statusText,
+ response.status,
+ result.error?.type || "ApiError"
+ );
+ }
+
+ return result.data;
+ }
+
+ /**
+ * Service health check.
+ *
+ * @returns {Promise