npm package: @keysense/sdk
Description: Official JavaScript/TypeScript SDK for the KeySense AI keyboard layout detection API
Author: Aras Hatemi
Latest version: 0.2.0

# @keysense/sdk

> Official JavaScript / TypeScript SDK for the [KeySense AI](https://github.com/rshatemi/keysense-ai) keyboard layout detection API.

[![npm](https://img.shields.io/npm/v/@keysense/sdk?color=blue)](https://www.npmjs.com/package/@keysense/sdk)
[![License](https://img.shields.io/badge/license-MIT-purple)](../../LICENSE)

Typed `руддщ` when you meant `hello`? One call fixes it.

---

## Install

```bash
npm install @keysense/sdk
```

---

## Quick start

```typescript
import { KeySenseClient } from '@keysense/sdk';

const ks = new KeySenseClient();

const result = await ks.detect('руддщ цщкдв');
console.log(result.decoded);       // 'hello world'
console.log(result.layout);        // 'ru-RU'
console.log(result.confidence);    // 0.97
console.log(result.word_coverage); // 1.0
```

---

## API

### `new KeySenseClient(config?)`

```typescript
const ks = new KeySenseClient({
  apiUrl:       'https://keysense-ai.keysense-ai.workers.dev', // default
  timeout:      10_000,      // ms, default 10s
  maxRetries:   2,           // retries on 5xx / network errors
  defaultUseAI: false,       // force Claude AI on every request
  fetch:        customFetch, // optional custom fetch (e.g. node-fetch)
});
```

---

### `ks.detect(text, options?)`

Detect the keyboard layout and return the corrected text.

```typescript
const result = await ks.detect('руддщ', {
  useAI:  true,              // force Claude AI verification
  signal: abortCtrl.signal,  // optional AbortSignal
});
```

**Returns `DetectResult`:**

```typescript
{
  decoded:    'hello',       // corrected text
  layout:     'ru-RU',       // detected source layout
  confidence: 0.97,          // 0–1
  ai_used:    false,         // was Claude invoked?
  processing_ms: 1,          // rule-based processing time (ms)
  word_coverage: 1.0,        // fraction of words matched against dictionary (Layer 8)
  keyboard_profile: {        // detected physical keyboard type (Layer 7)
    profile:    'ansi-104',
    confidence: 0.8,
  },
  candidates: [              // top alternative decodings (up to 3)
    { layout: 'ru-RU', text: 'hello', confidence: 0.97, word_coverage: 1.0 },
  ],
  original:  'руддщ',        // original input (added by SDK)
  unchanged: false,          // true if no correction was applied
}
```

---

### `ks.health()`

Check the worker status and number of loaded layouts.

```typescript
const h = await ks.health();
// { status: 'ok', layouts_loaded: 70, version: '0.2.0', timestamp: '...' }
```

---

### `ks.layouts()`

List all 70 supported layouts with writing direction and priority.

```typescript
const { count, layouts } = await ks.layouts();
// count: 70
// layouts: [{ id: 'ru-RU', name: 'Russian', direction: 'ltr', priority: 9 }, ...]
```

---

## Error handling

All errors thrown by the SDK are instances of `KeySenseError`:

```typescript
import { KeySenseClient, KeySenseError } from '@keysense/sdk';

try {
  const result = await ks.detect(text);
} catch (err) {
  if (err instanceof KeySenseError) {
    console.error(err.code);      // 'NETWORK_ERROR' | 'TIMEOUT' | 'RATE_LIMITED'
                                  // | 'INVALID_INPUT' | 'SERVER_ERROR' | 'ABORTED'
    console.error(err.message);
    console.error(err.status);    // HTTP status if applicable
    console.error(err.retryable); // true if safe to retry
  }
}
```

---

## Supported layouts (70)

Russian, Ukrainian, Belarusian, Arabic, Hebrew, Persian, German, French, Spanish, Polish, Turkish, Greek, Armenian, Georgian, Japanese, Korean, Chinese (Traditional), Thai, Vietnamese, and many more. Full list at [`GET /layouts`](https://keysense-ai.keysense-ai.workers.dev/layouts).

---

## Use with Node.js < 18

Node.js 18+ has native `fetch`. For older versions, pass a custom fetch:

```typescript
import fetch from 'node-fetch';
import { KeySenseClient } from '@keysense/sdk';

const ks = new KeySenseClient({ fetch: fetch as typeof globalThis.fetch });
```

---

## License

MIT © 2026 Aras Hatemi