npm package: @gzl10/baserow
Description: Modern TypeScript client for Baserow API with 3-client architecture, 21 field types, and optimized bulk operations
Author: Gonzalo Díez
Latest version: 1.2.2

# @gzl10/baserow

[![npm version](https://img.shields.io/npm/v/@gzl10/baserow.svg)](https://www.npmjs.com/package/@gzl10/baserow)
[![npm downloads](https://img.shields.io/npm/dm/@gzl10/baserow.svg)](https://www.npmjs.com/package/@gzl10/baserow)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.6-blue.svg)](https://www.typescriptlang.org/)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
[![Pipeline Status](https://gitlab.gzl10.com/oss/baserow/badges/main/pipeline.svg)](https://gitlab.gzl10.com/oss/baserow/-/pipelines)

Modern TypeScript client for Baserow API v1.35+ with **3-client architecture**, **PrismaBaserowMapper**, **21/22 field types**, and **automatic JWT refresh**.

## Features

- 🎯 **3-Client Architecture**: Token, Admin Global, and Admin Workspace
- 🔐 **Auto-Refresh JWT**: Automatic access/refresh token management
- 🗺️ **PrismaBaserowMapper**: Familiar Prisma-style query syntax (35+ tests)
- 📋 **21/22 Field Types**: Complete coverage including file, autonumber, count, rollup, lookup
- 🚀 **Optimized HTTP**: axios-retry + axios-rate-limit (36% less code)
- 🔄 **Hierarchical API**: Intuitive workspace → database → table → fields/rows navigation
- ⚡ **Bulk Operations**: Optimized batch processing with retry logic

## Installation

```bash
pnpm add @gzl10/baserow
```

## Quick Start

```typescript
import { BaserowClient } from '@gzl10/baserow'

// 1. Database Token (read-only)
const client = await BaserowClient.create({
  url: 'https://baserow.example.com',
  token: 'db_token_123'
})

// 2. Admin Global (multi-workspace)
const admin = await BaserowClient.create({
  url: 'https://baserow.example.com',
  credentials: { email: 'admin@example.com', password: 'password' }
})

// 3. Admin Workspace (scoped)
const adminWS = await BaserowClient.create({
  url: 'https://baserow.example.com',
  credentials: { email: 'admin@example.com', password: 'password' },
  workspace: 'My Workspace'
})
```

## Client Types

| Client             | Auth           | Capabilities                         | Use Cases                    |
| ------------------ | -------------- | ------------------------------------ | ---------------------------- |
| **BaserowClient**  | Database Token | Data CRUD, bulk operations           | Apps, data integration, APIs |
| **AdminGlobal**    | JWT Multi-WS   | Full workspace/database/table mgmt   | Admin scripts, DevOps tools  |
| **AdminWorkspace** | JWT Scoped     | Operations within specific workspace | Enterprise apps, dashboards  |

## PrismaBaserowMapper

Familiar Prisma-style syntax for Baserow queries:

```typescript
const employees = await client
  .database(123)
  .table(456)
  .rows.findMany({
    where: {
      AND: [{ status: 'active' }, { age: { gte: 18, lt: 65 } }, { email: { contains: '@company.com' } }]
    },
    orderBy: [{ created_at: 'desc' }, { name: 'asc' }],
    take: 20,
    skip: 40
  })
```

**Supported operators:** `equals`, `not`, `contains`, `startsWith`, `endsWith`, `gt`, `gte`, `lt`, `lte`, `AND`, `OR`, `NOT`, `isEmpty`, `isNotEmpty`

## Basic Usage

### Data Operations (Token Client)

```typescript
const rows = await client.database(123).table(456).rows.list()

const newRow = await client.database(123).table(456).rows.create({
  name: 'John Doe',
  email: 'john@example.com'
})

// Bulk operations
const bulkRows = await client.database(123).table(456).rows.createBulk(items, { batchSize: 100 })
```

### Admin Operations

```typescript
// Workspaces
const workspaces = await admin.workspaces.list()
const newWS = await admin.workspaces.create({ name: 'New Company' })

// Databases
const database = await admin.workspace('Company').databases.create('CRM')

// Tables
const table = await admin
  .workspace('Company')
  .database('CRM')
  .tables.create({
    name: 'Customers',
    data: [
      ['Name', 'Email'],
      ['Alice', 'alice@example.com']
    ],
    first_row_header: true
  })
```

## Field Types (21/22)

### Text & Communication

```typescript
await table.field.createText('full_name')
await table.field.createLongText('description')
await table.field.createUrl('website')
await table.field.createEmail('contact_email')
await table.field.createPhoneNumber('phone')
```

### Numeric & Boolean

```typescript
await table.field.createNumber('price', 2) // 2 decimals
await table.field.createBoolean('is_active')
await table.field.createRating('rating', 5)
```

### Date & Audit

```typescript
await table.field.createDate('birthdate')
await table.field.createLastModified('updated_at')
await table.field.createCreatedOn('created_at')
```

### Selection

```typescript
await table.field.createSingleSelect('status', [
  { value: 'active', color: 'green' },
  { value: 'inactive', color: 'red' }
])
await table.field.createMultipleSelect('tags', options)
```

### Relational

```typescript
await table.field.createLinkRow('related_items', targetTableId)
await table.field.createFormula('total', 'field("qty") * field("price")')
```

### Advanced

```typescript
await table.field.createFile('documents')
await table.field.createAutonumber('ticket_id')
await table.field.createCount('items_count', targetTableId)
await table.field.createRollup('total_amount', tableId, fieldId, 'sum')
await table.field.createLookup('item_names', tableId, fieldId)
```

## Configuration

### Performance Presets

```typescript
import { BaserowClient, PERFORMANCE_PRESETS } from '@gzl10/baserow'

const client = await BaserowClient.create({
  url: 'https://baserow.example.com',
  token: 'your_token',
  performance: PERFORMANCE_PRESETS.production
})
```

| Preset         | Timeout | Retries | Rate (req/s) |
| -------------- | ------- | ------- | ------------ |
| `production`   | 30s     | 3       | 10           |
| `development`  | 60s     | 2       | 5            |
| `testing`      | 45s     | 2       | 5            |
| `aggressive`   | 15s     | 5       | 20           |
| `conservative` | 60s     | 1       | 2            |

### Keep-Alive (24/7 Backends)

```typescript
const client = await BaserowClient.create({
  url: 'https://baserow.example.com',
  credentials: { email: 'backend@example.com', password: 'password' },
  keepAlive: {
    enabled: true,
    intervalMinutes: 7200 // Re-login every 5 days
  }
})
```

⚠️ **Baserow limitation**: Refresh token expires 7 days after login (fixed). Keep-alive performs automatic re-login to prevent expiration.

## Express Utilities (Optional)

```typescript
import { BaserowClient, express as baserowExpress } from '@gzl10/baserow'

app.use('/api', baserowExpress.baserowContext(client))
app.use('/api', baserowExpress.requireAuth())

app.get('/api/rows', async (req, res) => {
  const rows = await req.baserow!.database(123).table(456).rows.list()
  res.json(baserowExpress.serializePaginated(rows))
})

app.use(baserowExpress.errorHandler())
```

## Error Handling

```typescript
import {
  BaserowError,
  BaserowNotFoundError,
  BaserowValidationError,
  BaserowAuthTokenExpiredError
} from '@gzl10/baserow'

try {
  await client.database(999).table(456).rows.list()
} catch (error) {
  if (error instanceof BaserowNotFoundError) {
    console.error('Resource not found:', error.message)
  }
}
```

## Testing

```bash
pnpm test           # All tests
pnpm test:watch     # Watch mode
pnpm test:smoke     # CI/CD smoke tests
```

60+ tests including 35+ integration tests and 34 error handling tests.

## Documentation

- [Filters & Sorting](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/FILTERS_AND_SORTING.md)
- [API Reference](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/BASEROW_API_REFERENCE.md)
- [Keep-Alive Guide](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/KEEP_ALIVE.md)
- [Migration Guide](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/MIGRATION.md)
- [Testing Guide](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/TESTING.md)
- [Debugging](https://gitlab.gzl10.com/oss/baserow/-/blob/main/docs/DEBUGGING.md)

## Compatibility

✅ **Baserow v1.35.3** - Fully compatible, safe upgrade from v1.35.0+

## Support

<a href="https://www.buymeacoffee.com/gzl10g" target="_blank"><img src="https://cdn.buymeacoffee.com/buttons/v2/default-yellow.png" alt="Buy Me A Coffee" style="height: 60px !important;width: 217px !important;" ></a>

## License

MIT License - See [LICENSE](LICENSE)