npm package: @kemetsoft/ankhdb-js
Description: The official JavaScript SDK for AnkhDB - Real-time Multi-tenant BaaS.
Author: KemetSoft
Latest version: 2.0.2

# @kemetsoft/ankhdb-js

[![npm version](https://img.shields.io/npm/v/@kemetsoft/ankhdb-js.svg)](https://www.npmjs.com/package/@kemetsoft/ankhdb-js)

The official JavaScript / TypeScript SDK for **AnkhDB** — a self-hosted, multi-tenant Backend-as-a-Service with Auth, Database, Storage, and Edge Functions.

## Installation

```bash
npm install @kemetsoft/ankhdb-js
```

## Quick Start

Find your **Project ID** and **API Key** in the AnkhDB Dashboard → **Settings**.

```javascript
import AnkhDB from '@kemetsoft/ankhdb-js';

const db = new AnkhDB('YOUR_PROJECT_ID', 'YOUR_API_KEY');
// Self-hosted: new AnkhDB('proj_...', 'ankh_sec_...', { serverUrl: 'http://localhost:5000' })
```

---

## Error Handling

All errors throw typed exceptions derived from `AnkhDBError`:

```javascript
import { AuthError, NotFoundError, RateLimitError } from '@kemetsoft/ankhdb-js';

try {
  await db.login('user@example.com', 'wrong');
} catch (err) {
  if (err instanceof AuthError)      console.log('Bad credentials');
  if (err instanceof RateLimitError) console.log('Slow down!');
  console.log(err.status, err.message);
}
```

| Class | HTTP Status |
|---|---|
| `AnkhDBError` | base (all errors) |
| `ValidationError` | 400 |
| `AuthError` | 401 |
| `PermissionError` | 403 |
| `NotFoundError` | 404 |
| `RateLimitError` | 429 |
| `ServerError` | 5xx |

---

## Authentication

```javascript
await db.register('user@example.com', 'password');
await db.login('user@example.com', 'password');
const { user } = await db.getSession();
db.logout();
```

---

## Database — Query Builder

`db.from(collection)` returns a **chainable `AnkhQuery`**:

```javascript
const posts = db.from('posts');

// Basic CRUD
const doc  = await posts.insert({ title: 'Hello', views: 0 });
const all  = await posts.select();
const one  = await posts.get(doc.id);
await posts.update(doc.id, { views: 1 });
await posts.delete(doc.id);

// Filters
const popular = await db.from('posts')
  .gt('views', 100)
  .eq('status', 'published')
  .select();

// Pagination
const page2 = await db.from('posts').limit(10).offset(10).select();

// Join (embed related collection)
const withComments = await db.from('posts')
  .join('comments', 'postId')   // embed comments where comments.postId === post.id
  .select();

// Realtime subscription
const es = db.from('posts').subscribe((event) => {
  console.log(event.event, event.data); // INSERT / UPDATE / DELETE
});
// es.close() to unsubscribe
```

---

## Storage

```javascript
const file     = document.querySelector('input[type=file]').files[0];
const uploaded = await db.storage.upload(file);
console.log(uploaded.url);

const files = await db.storage.list();
await db.storage.delete(uploaded.id);
```

---

## Edge Functions

```javascript
const res = await db.functions.invoke('greet', { name: 'Alice' });
console.log(res.result);
```

---

## API Reference

| Method | Description |
|---|---|
| `new AnkhDB(projectId, apiKey, options?)` | Create a client |
| `db.from(collection)` | Get an `AnkhQuery` builder |
| `query.eq/neq/gt/gte/lt/lte(field, val)` | Add a filter |
| `query.limit(n)` / `query.offset(n)` | Paginaton |
| `query.join(col, fkField)` | Embed related docs |
| `query.select()` | Fetch documents |
| `query.insert(data)` | Create a document |
| `query.update(id, data)` | Update a document |
| `query.delete(id)` | Delete a document |
| `query.subscribe(cb)` | SSE realtime stream |
| `db.storage.upload(file)` | Upload a file |
| `db.storage.list()` | List files |
| `db.storage.delete(id)` | Delete a file |
| `db.functions.invoke(name, payload?)` | Call an Edge Function |

---

## License

MIT © KemetSoft