Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.ondb.ai/llms.txt

Use this file to discover all available pages before exploring further.

Authentication

Use App Key Auth

Use appKey for writes. Use agentKey for autonomous agent operations. Never expose keys in client-side code.
// Server-side
const client = createClient({
  endpoint: process.env.ONDB_ENDPOINT,
  appId: process.env.ONDB_APP_ID,
  appKey: process.env.ONDB_APP_KEY
});

Indexes

Create Indexes FirstYou MUST create at least one index per collection. Without indexes, queries perform full collection scans and the dashboard cannot display collections. Create indexes BEFORE storing data.
// Always create indexes before storing data
const db = client.database('my-app');

await db.createIndex({
  name: 'idx_users_email',
  collection: 'users',
  field_name: 'email',
  index_type: 'hash',
  unique_constraint: true,
  store_values: true
});

// Index fields you'll query
await db.createIndex({
  name: 'idx_users_createdAt',
  collection: 'users',
  field_name: 'createdAt',
  index_type: 'btree'
});

// Now store data
await client.store({ collection: 'users', data: [...] });

Payment Handling

Handle Payment Callbacks

Implement payment callbacks for store operations. Handle PaymentRequiredError for read operations.
// Write operations - server provides quote, caller handles USDC payment
await client.store(
  { collection: 'data', data },
  async (quote) => {
    const txHash = await processPayment(quote);
    return { txHash, network: quote.network, sender: walletAddress, chainType: quote.chainType, paymentMethod: 'native' };
  },
  true
);

// Read operations
try {
  const result = await client.queryBuilder()
    .collection('premium_data')
    .execute();
} catch (error) {
  if (error instanceof PaymentRequiredError) {
    // Handle payment flow
    const paymentInfo = error.paymentRequired;
    // ...
  }
}

Error Handling

Use Specific Error Types

Always implement proper error handling with specific error types.
import {
  ValidationError,
  TransactionError,
  PaymentRequiredError,
  OnDBError
} from '@ondb/sdk';

try {
  await client.store(data, paymentCallback);
} catch (error) {
  if (error instanceof ValidationError) {
    // Handle validation errors
  } else if (error instanceof TransactionError) {
    // Handle transaction failures
  } else if (error instanceof PaymentRequiredError) {
    // Handle payment flow
  } else if (error instanceof OnDBError) {
    // Handle other SDK errors
  }
}

Query Optimization

Use Query Builder for All Queries

Use the QueryBuilder fluent API for all read operations.
// Simple queries
const user = await client.queryBuilder()
  .collection('users')
  .whereField('email').equals('alice@example.com')
  .executeUnique();

// Complex queries
const results = await client.queryBuilder()
  .collection('orders')
  .whereField('status').equals('completed')
  .whereField('createdAt').greaterThanOrEqual(new Date(new Date().getFullYear(), new Date().getMonth(), 1).toISOString())
  .joinOne('customer', 'users')
    .onField('id').equals('$data.customerId')
    .selectFields(['name', 'email'])
    .build()
  .selectAll()
  .limit(50)
  .execute();

Async Operations

Use Task Tickets for Long Operations

Use task tickets for long-running operations and monitor progress.
// Non-blocking store
const response = await client.store(data, paymentCallback, false);

// Monitor progress
const status = await client.getTaskStatus(response.ticket_id);

// Or wait for completion
const task = await client.waitForTaskCompletion(response.ticket_id);

Cost Awareness

Inspect Costs via Payment Callback

The payment callback receives a quote with full cost details before you authorize payment.
await client.store(
  { collection: 'users', data },
  async (quote) => {
    if (quote.totalCost > maxBudget) {
      throw new Error(`Operation costs ${quote.totalCost} ${quote.tokenSymbol}, exceeds budget`);
    }
    const txHash = await processPayment(quote);
    return { txHash, network: quote.network, sender: walletAddress, chainType: quote.chainType, paymentMethod: 'native' };
  },
  true
);

PriceIndex for Commerce

Use PriceIndex for Revenue Sharing

Use PriceIndex when building commerce platforms, ticketing systems, or apps with revenue sharing.
// Create PriceIndex on payment field
await db.createIndex({
  name: 'idx_orders_total',
  collection: 'orders',
  field_name: 'totalPrice',
  index_type: 'price'
});

// Payment = field value, not storage cost
await client.store(
  { collection: 'orders', data: [{ totalPrice: 100000000, items: [...] }] },
  paymentCallback,
  true
);

TypeScript

Leverage Type Safety

Use TypeScript for full type safety and better development experience.
interface User {
  id: string;
  email: string;
  name: string;
  createdAt: string;
}

const user = await client.queryBuilder()
  .collection('users')
  .whereField('email').equals('alice@example.com')
  .executeUnique<User>();
// user is User | null with full IntelliSense

const users = await client.queryBuilder()
  .collection('users')
  .whereField('active').isTrue()
  .execute<User>();
// users.records is User[]

Batch Operations

Use Batches for Bulk Data

Use batch operations for large datasets to improve efficiency.
// Store multiple records in a single call
await client.store(
  { collection: 'products', data: products },
  paymentCallback,
  true
);

// For large datasets, chunk into batches
const BATCH_SIZE = 100;
for (let i = 0; i < products.length; i += BATCH_SIZE) {
  const chunk = products.slice(i, i + BATCH_SIZE);
  await client.store({ collection: 'products', data: chunk }, paymentCallback, true);
  console.log(`${Math.min(i + BATCH_SIZE, products.length)}/${products.length}`);
}

Transaction Monitoring

Monitor Transactions in Real-Time

Use event listeners to track transaction status in real-time.
client.on('transaction:queued', (ticket) => {
  console.log(`Task ${ticket.ticket_id} queued`);
});

client.on('transaction:confirmed', (tx) => {
  console.log(`Confirmed at block ${tx.block_height}`);
});

client.on('transaction:failed', (tx) => {
  console.error(`Failed: ${tx.error}`);
});

Checklist

  • Create indexes before storing data
  • Use environment variables for keys
  • Implement payment callbacks
  • Handle all error types
  • Use TypeScript for type safety
  • Get cost estimates before operations
  • Monitor transactions with events
  • Use batch operations for bulk data
  • Consider PriceIndex for commerce apps