npm package: @rebarxyz/sdk
Description: > **TypeScript SDK for building decentralized data networks with automated logic**
Latest version: 0.0.28

# Rebar SDK

> **TypeScript SDK for building decentralized data networks with automated logic**

Rebar lets you create interconnected data nodes that automatically calculate, trigger actions, and react to changes—all on-chain. Perfect for DeFi strategies, IoT monitoring, financial modeling, and automation workflows.

## 🚀 Quick Start

```bash
npm install @rebarxyz/sdk
```

```typescript
import { RebarClient } from '@rebarxyz/sdk';
import { HDWallet } from '@rebarxyz/rivet/wallet';

// Connect to network (read-only)
const client = new RebarClient('https://rpc.rebar.xyz');

// Or with wallet for transactions
const wallet = HDWallet.fromMnemonic(process.env.MNEMONIC!, { prefix: 'rebar' });
const client = new RebarClient('https://rpc.rebar.xyz', wallet, 'rebar1...');
```

## 🏗️ Core Concepts

Rebar organizes data into **5 node types** that work together:

| Node Type | Purpose | Example |
|-----------|---------|---------|
| **Input** | Store live data | Temperature sensor, price feed |
| **Calculated** | Auto-compute from inputs | Moving average, portfolio value |
| **Function** | Execute complex logic | Risk assessment, data processing |
| **Action** | Define external tasks | Send alert, execute trade |
| **Trigger** | Monitor & activate actions | Alert when price > $100 |

## 📊 Build Your First Network

### Example: DeFi Price Monitor

```typescript
// 1. Create price input (updated by oracle)
const btcPrice = await client.createData({
  name: 'BTC/USD Price',
  description: 'Live Bitcoin price from CoinGecko',
  valueType: 'float',
  value: '45000'
});

// 2. Calculate price threshold (simple calculation)
const priceThreshold = await client.createCalculation({
  name: 'Price Threshold (45k)',
  description: 'Fixed threshold for price alerts',
  inputs: [],
  calculationType: 'expression',
  calculation: '45000.0',
  valueType: 'float'
});

// 3. Define alert action
const alertAction = await client.createAction({
  name: 'Price Alert',
  description: 'Send notification when price changes significantly',
  schema: JSON.stringify({
    type: 'object',
    properties: { 
      message: { type: 'string' },
      price: { type: 'number' }
    }
  }),
  cost: '0',
  completionValidation: 'signer'
});

// 4. Create trigger for price above threshold
const priceTrigger = await client.createTrigger({
  name: 'High Price Alert',
  description: 'Trigger when price exceeds threshold',
  inputs: [btcPrice.address, priceThreshold.address],
  triggerLogic: `${btcPrice.address} > ${priceThreshold.address}`,
  triggerLogicType: 'expression',
  action: alertAction.address
});

// 5. Update price (triggers calculation cascade)
await client.addData({
  address: btcPrice.address,
  value: '47250'
});
```

## 🔧 SDK Methods

### Node Creation

All creation methods return the transaction response by default, or expanded response with `{ expanded: true }`:

```typescript
// Input nodes - store updatable data
const sensor = await client.createData({
  name: 'Temperature Sensor',
  valueType: 'float',
  value: '22.5',
  validation: 'signer' // or 'anyone', 'owner'
});

// Calculated nodes - auto-compute from inputs
const fahrenheit = await client.createCalculation({
  name: 'Temperature (°F)',
  inputs: [sensor.address],
  calculationType: 'expression', // or 'starlark'
  calculation: `${sensor.address} * 9/5 + 32`,
  valueType: 'float'
});

// Function nodes - complex logic with state
const processor = await client.createFunction({
  name: 'Temperature Processor',
  calculation: `
def process_temp(temp, state):
    # Simple processing - double the temperature
    return temp * 2.0
return process_temp(${sensor.address}, state)`,
  calculationType: 'starlark',
  inputs: [sensor.address],
  state: JSON.stringify({ lastReading: 0 })
});

// Action nodes - external tasks
const notification = await client.createAction({
  name: 'SMS Alert',
  schema: JSON.stringify({
    type: 'object',
    properties: { 
      recipient: { type: 'string' },
      message: { type: 'string' }
    }
  }),
  cost: '100urebar',
  completionValidation: 'anyone'
});

// Trigger nodes - conditional activation
const trigger = await client.createTrigger({
  name: 'High Temperature Alert',
  inputs: [fahrenheit.address],
  triggerLogic: `${fahrenheit.address} > 85.0`,
  triggerLogicType: 'expression',
  action: notification.address
});
```

### Data Operations

```typescript
// Read node values (type-safe with generics)
const temp = await client.getValue<number>(sensor.address);
const node = await client.getNode(sensor.address);
const allNodes = await client.getAllNodes();

// Update input nodes
await client.addData({
  address: sensor.address,
  value: '25.3'
});

// Batch updates (more efficient)
await client.addDataBatch([
  { address: sensor1.address, value: '23.1', signer: signerAddress, nonce: 1 },
  { address: sensor2.address, value: '24.8', signer: signerAddress, nonce: 2 }
]);

// One-off calculations (no node creation)
const result = await client.runCalculation({
  valueType: 'float',
  calculationType: 'expression',
  calculation: 'temp * 1.8 + 32',
  inputs: [sensor.address]
});

// Complete triggered actions
await client.completeTriggerAction({
  triggerAddress: trigger.address,
  actionAddress: notification.address
});
```

## 📡 Real-time Monitoring

WebSocket support for live updates:

```typescript
// Watch for new blocks
const blockWatcher = client.watchBlocks(() => {
  console.log('New block mined');
});

// Watch specific nodes for recalculations
const recalcWatcher = client.watchRecalcs([sensor.address, fahrenheit.address], () => {
  console.log('Node values updated');
});

// Watch for trigger activations
const triggerWatcher = client.watchTriggers((event) => {
  console.log(`Trigger ${event.triggerAddress} activated`);
  console.log(`Action needed: ${event.actionAddress}`);
  console.log(`Data: ${event.actionData}`);
}, [trigger.address]); // Optional: filter by trigger

// Clean up
blockWatcher.close();
recalcWatcher.close();
triggerWatcher.close();
```

## 🛡️ Error Handling

SDK errors include a stable string `code` and optional `details` for programmatic handling.

```typescript
import { RebarClient, isRebarError, REBAR_ERROR_CODES } from '@rebarxyz/sdk';

try {
  const client = new RebarClient('https://rpc.rebar.xyz');
  await client.createData({ name: 'Temp', valueType: 'float', value: '72.1' });
} catch (err) {
  if (isRebarError(err)) {
    if (err.code === REBAR_ERROR_CODES.walletRequired) {
      console.error('Connect a wallet before sending transactions.');
    }
    console.error(err.code, err.details);
    return;
  }
  throw err;
}
```

## 🎯 Type Generation CLI

Generate type-safe interfaces for your nodes:

```bash
# Initialize config
npx @rebarxyz/sdk/cli --init

# Edit rebar.config.json
{
  "baseUrl": "https://rpc.rebar.xyz",
  "nodes": {
    "btcPrice": "rebar1abc...",
    "ethPrice": "rebar1def..."
  },
  "output": "./src/rebar-types.ts"
}

# Generate types
npx @rebarxyz/sdk/cli
```

Use generated types:

```typescript
import { btcPrice, ethPrice, type BtcPrice, type EthPrice } from './rebar-types';

// Fully type-safe node access
const currentBtc = await client.getValue<BtcPrice>(btcPrice);
const currentEth = await client.getValue<EthPrice>(ethPrice);
```

## 🔄 Advanced Examples

### Portfolio Tracker

```typescript
// Portfolio inputs
const btcHoldings = await client.createData({ name: 'BTC Holdings', valueType: 'float', value: '0.5' });
const ethHoldings = await client.createData({ name: 'ETH Holdings', valueType: 'float', value: '10' });
const btcPrice = await client.createData({ name: 'BTC Price', valueType: 'float', value: '45000' });
const ethPrice = await client.createData({ name: 'ETH Price', valueType: 'float', value: '3000' });

// Portfolio value calculation
const portfolioValue = await client.createCalculation({
  name: 'Total Portfolio Value',
  inputs: [btcHoldings.address, ethHoldings.address, btcPrice.address, ethPrice.address],
  calculationType: 'expression',
  calculation: `${btcHoldings.address} * ${btcPrice.address} + ${ethHoldings.address} * ${ethPrice.address}`,
  valueType: 'float'
});

// Rebalancing trigger
const rebalanceAction = await client.createAction({
  name: 'Rebalance Portfolio',
  schema: JSON.stringify({ type: 'object', properties: { action: { type: 'string' } } }),
  cost: '0',
  completionValidation: 'signer'
});

const rebalanceTrigger = await client.createTrigger({
  name: 'Portfolio Imbalance Detector',
  inputs: [btcHoldings.address, ethHoldings.address, btcPrice.address, ethPrice.address, portfolioValue.address],
  triggerLogic: `
btc_value = ${btcHoldings.address} * ${btcPrice.address}
btc_percent = btc_value / ${portfolioValue.address}
target_percent = 0.6
diff = btc_percent - target_percent
# Check if difference is greater than 10% (0.1)
return diff > 0.1 or diff < -0.1`,
  triggerLogicType: 'starlark',
  action: rebalanceAction.address
});
```

### IoT Sensor Network

```typescript
// Multiple sensor inputs
const sensors = await Promise.all([
  client.createData({ name: 'Living Room Temp', valueType: 'float', value: '22' }),
  client.createData({ name: 'Bedroom Temp', valueType: 'float', value: '20' }),
  client.createData({ name: 'Kitchen Temp', valueType: 'float', value: '24' })
]);

// Average temperature using Starlark's mean function
const avgTemp = await client.createCalculation({
  name: 'House Average Temperature',
  inputs: sensors.map(s => s.address),
  calculationType: 'starlark',
  calculation: `
temp_list = [${sensors.map(s => s.address).join(', ')}]
return mean(temp_list)`,
  valueType: 'float'
});

// HVAC control action
const hvacControl = await client.createAction({
  name: 'HVAC Control',
  schema: JSON.stringify({
    type: 'object',
    properties: {
      action: { type: 'string', enum: ['heat', 'cool', 'off'] },
      targetTemp: { type: 'number' }
    }
  }),
  cost: '50urebar',
  completionValidation: 'anyone'
});

// Temperature control triggers
const coolTrigger = await client.createTrigger({
  name: 'Cooling Trigger',
  inputs: [avgTemp.address],
  triggerLogic: `${avgTemp.address} > 25.0`,
  triggerLogicType: 'expression',
  action: hvacControl.address
});
```

## 🔒 Error Handling

```typescript
import { NodeNotFoundError, WalletRequiredError } from '@rebarxyz/sdk';

try {
  const value = await client.getValue('rebar1invalid...');
} catch (error) {
  if (error instanceof NodeNotFoundError) {
    console.log('Node not found');
  } else if (error instanceof WalletRequiredError) {
    console.log('Transaction requires wallet');
  }
}
```

## 🌐 Network Support

- **Mainnet**: `https://rpc.rebar.xyz`
- **Testnet**: `https://testnet-rpc.rebar.xyz`
- **Local**: `http://localhost:26657`

## 📚 API Reference

### Client Options

```typescript
const client = new RebarClient(
  'https://rpc.rebar.xyz',  // RPC endpoint
  wallet,                   // Optional: OfflineDirectSigner (e.g. HDWallet/Keplr/Leap)
  'rebar1...',             // Optional: default signer address
  { errorMode: 'safe' }    // Optional: 'safe' (default) | 'strict'
);

await client.ready(); // Wait for full initialization (optional)
```

Per-call override for search/query methods:

```typescript
const strictPage = await client.searchNodeUpdates(
  { address: 'rebar1...', limit: 20 },
  { errorMode: 'strict' }
);
```

### Transaction Options

All transaction methods support an optional `options` parameter:

```typescript
// Get expanded response with transaction details
const response = await client.createData(params, { expanded: true });
console.log(response.txHash, response.height, response.gasUsed);

// Get just the message response (default)
const response = await client.createData(params);
console.log(response.address);
```

### Value Types

Supported `valueType` options for nodes:

- **Primitives**: `string`, `int`, `float`, `bool`, `uint256`
- **Arrays**: `string[]`, `int[]`, `float[]`, `bool[]`, `uint256[]`
- **Complex**: `json`, `json[]`

### Calculation Types

- **`expression`**: Simple mathematical expressions with node addresses
- **`starlark`**: Python-like scripting with basic built-ins: `sum`, `mean`, `pow`

## 🛠️ Development

```bash
# Build SDK
bun run build

# Run tests  
bun test

# Generate types from chain
bun run generate-types
```

## 📄 License

MIT License - see LICENSE file for details.