# @bounded-sh/server

Server SDK for the Bounded API. It provides explicit, isolated Solana-keypair clients for backend applications; no signer is loaded from ambient process state.

## Installation

```bash
npm install @bounded-sh/server
```

Or using yarn:

```bash
yarn add @bounded-sh/server
```

## Features

- Server-side authentication using Solana keypairs (SIWS)
- In-memory session management (no cookies or local storage required)
- Support for all Tarobase data operations (get, getMany, set, query)
- Real-time subscriptions
- Transaction signing and execution
- TypeScript support

## Basic Usage

```typescript
import { init, createWalletClient } from '@bounded-sh/server';

async function main() {
  // Initialize endpoints/app config only. Server signing identity is explicit.
  await init({ appId: 'your-app-id' });

  // Create a wallet-scoped client from an explicit secret key.
  const wallet = await createWalletClient({ keypair: process.env.SERVER_WALLET_KEYPAIR! });
  console.log(`Using wallet: ${wallet.address}`);

  // Set data
  await wallet.set('todos/123', {
    text: 'Buy milk', 
    completed: false, 
    created: new Date().toISOString() 
  });

  // Get data
  const todo = await wallet.get('todos/123');
  console.log('Retrieved todo:', todo);
}

main().catch(console.error);
```

## Advanced Usage

### Loading a Keypair from a Secret Key File

```typescript
import { init, createWalletClient } from '@bounded-sh/server';
import * as fs from 'fs';

// Load keypair from file
const secretKeyString = fs.readFileSync('/path/to/keypair.json', 'utf8');

// Initialize and create a wallet-scoped client
await init({ appId: 'your-app-id' });
const wallet = await createWalletClient({ keypair: secretKeyString });
```

### Signing And Transactions

```typescript
import { init, createWalletClient } from '@bounded-sh/server';

await init({
  appId: 'your-app-id',
  rpcUrl: process.env.SOLANA_MAINNET_RPC_URL
});

const wallet = await createWalletClient({ keypair: process.env.SERVER_WALLET_KEYPAIR! });

// Sign a message
const signature = await wallet.signMessage("Hello, world!");

// Submit a transaction you built explicitly with @solana/web3.js
// const signature = await wallet.signAndSubmitTransaction(transaction);
```

### Subscriptions

```typescript
import { init, createWalletClient } from '@bounded-sh/server';

// Initialize and create an explicit wallet client
await init({ appId: 'your-app-id' });
const wallet = await createWalletClient({ keypair: process.env.SERVER_WALLET_KEYPAIR! });

// Subscribe to changes
const unsubscribeFunc = await wallet.subscribe('todos', (data) => {
  console.log('Todos updated:', data);
});

// Later, unsubscribe when done
await unsubscribeFunc();
```

## API Reference

### Configuration and Initialization

```typescript
function init(config: Partial<ClientConfig>): Promise<void>;
function getConfig(): Promise<ClientConfig>;
function getWebhookKeysUrl(): string | undefined;
```

### Authentication

```typescript
function createWalletClient(options: { keypair: string }): Promise<WalletClient>;
function getAuthProvider(): Promise<AuthProvider>; // always rejects; no process-global provider
function getIdToken(): Promise<string | null>; // always rejects; no process-global session
```

### Data Operations

```typescript
const wallet = await createWalletClient({ keypair });
const idToken = await wallet.getIdToken(); // refreshed bearer token for direct Bounded API calls
await wallet.get(path);
await wallet.getMany(paths);
await wallet.set(path, data);
await wallet.setMany(many);
await wallet.setFile(path, file);
await wallet.getFiles(path);
await wallet.runQuery(absolutePath, queryName, queryArgs);
await wallet.runQueryMany(many);
```

### Subscriptions

```typescript
const unsubscribe = await wallet.subscribe(path, callback);
await unsubscribe();
```

### Solana Keypair Provider

```typescript
class SolanaKeypairProvider implements AuthProvider {
  constructor(rpcUrl: string | null, keypair: Keypair);

  login(): Promise<User | null>;
  logout(): Promise<void>;
  signMessage(message: string): Promise<string>;
  restoreSession(): Promise<User | null>;
  getNativeMethods(): Promise<any>;
}
```

`signAndSubmitTransaction` requires an explicit provider `rpcUrl`; a missing RPC
fails closed.

## Types

```typescript
interface ClientConfig {
  authMethod?: string;
  wsApiUrl: string;
  apiUrl: string;
  appId: string;
  authApiUrl: string;
  chain: string;
  rpcUrl: string;
  skipBackendInit: boolean;
  useSessionStorage: boolean;
}

interface User {
  address: string;
  provider: AuthProvider;
}

interface SetOptions {
  shouldSubmitTx?: boolean;
}

interface GetManyResult {
  path: string;
  data: any | null;
  error?: {
    code: 'NOT_FOUND' | 'UNAUTHORIZED' | 'INVALID_PATH';
    message: string;
  };
}

interface TransactionResult {
  transactionSignature?: string;
  signedTransaction?: any;
  blockNumber: number;
  gasUsed: string;
  data: any;
}
```

## Contributing

Please see the main repository for contribution guidelines.

## Key Differences from the Web SDK

This server-side SDK differs from the web SDK in several important ways:

1. **Authentication Method**: Uses explicit Solana keys instead of browser wallets
2. **Storage Strategy**: Uses in-memory storage instead of localStorage/sessionStorage 
3. **Environment**: Optimized for Node.js/backend environments rather than browsers
4. **Session Management**: Does not rely on browser-specific APIs
5. **Dependencies**: Excludes browser-specific libraries

## Part of the Bounded SDK Family

This package is part of a family of modular SDKs:

- **@bounded-sh/core**: Core functionality shared between all SDKs
- **@bounded-sh/client**: Browser and React Native SDK
- **@bounded-sh/server**: Server-side SDK for backend applications
