# @okrapdf/runtime

Small session-first SDK on top of the OkraPDF HTTP API.

## Install

```bash
npm install @okrapdf/runtime
```

## SDK Surface

Only two runtime entry points:

- `createOkra(...)` for document sessions
- `doc(...)` for deterministic document URLs

## Quick Start

```ts
import { createOkra } from '@okrapdf/runtime';

const okra = createOkra({ apiKey: process.env.OKRA_API_KEY });

const session = await okra.sessions.create('./report.pdf', {
  wait: true,
  model: 'kimi-k2p5',
});

const { answer } = await session.prompt('What is total revenue?');
console.log(answer);

const stream = session.stream('Summarize in 3 bullets');
for await (const event of stream) {
  if (event.type === 'text_delta') process.stdout.write(event.text);
}
```

## Structured Output (Zod)

```ts
import { z } from 'zod';

const Invoice = z.object({
  vendor: z.string(),
  total: z.number(),
});

const result = await session.prompt('Extract invoice fields', {
  schema: Invoice,
});

console.log(result.data?.vendor, result.data?.total);
```

## Share Links (Redacted Viewer vs Full Admin)

```ts
const viewer = await session.shareLink({
  role: 'viewer',
  expiresInMs: 24 * 60 * 60 * 1000,
});

const admin = await session.shareLink({
  role: 'admin',
  expiresInMs: 24 * 60 * 60 * 1000,
});

console.log(viewer.links.markdown, viewer.links.pdf);
console.log(admin.links.markdown, admin.links.pdf);
```

## Deterministic URL Builder

```ts
import { doc } from '@okrapdf/runtime';

const d = doc(session.id, { fileName: 'report.pdf' });

console.log(d.thumbnail.url());
console.log(d.pages[1].image.url());
console.log(d.entities.tables[0].url({ format: 'csv' }));
```

## curl Contract

The SDK maps directly to these endpoints.

### 1) Upload URL source

```bash
curl -X POST "https://api.okrapdf.com/document/ocr-demo/upload-url" \
  -H "Authorization: Bearer $OKRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://example.com/report.pdf",
    "visibility": "private",
    "redact": {
      "pii": {
        "preset": "hipaa",
        "patterns": ["SSN", "EMAIL", "PHONE_US"]
      }
    }
  }'
```

### 2) Wait for readiness

```bash
curl "https://api.okrapdf.com/document/ocr-demo/status" \
  -H "Authorization: Bearer $OKRA_API_KEY"
```

Poll until `phase` is `complete` (or `awaiting_review`).

### 3) Ask a question

```bash
curl -X POST "https://api.okrapdf.com/document/ocr-demo/completion" \
  -H "Authorization: Bearer $OKRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "What is total revenue?",
    "model": "kimi-k2p5"
  }'
```

### 4) Stream tokens

```bash
curl -N -X POST "https://api.okrapdf.com/document/ocr-demo/completion" \
  -H "Authorization: Bearer $OKRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "Summarize in 3 bullets",
    "stream": true,
    "model": "kimi-k2p5"
  }'
```

### 5) Create scoped share links

```bash
curl -X POST "https://api.okrapdf.com/document/ocr-demo/share-link" \
  -H "Authorization: Bearer $OKRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "role": "viewer",
    "expiresInMs": 86400000
  }'
```

Use `role: "admin"` for full-access links.

## Public API

```ts
createOkra({ apiKey, baseUrl?, sharedSecret?, fetch? }) => okra

okra.sessions.create(sourceOrDocId, { wait?, model?, upload?, waitOptions? }) => session
okra.sessions.from(docId, { model? }) => session

session.id
session.model
session.modelEndpoint
session.state()
session.setModel(model)
session.status()
session.wait()
session.pages()
session.page(n)
session.entities()
session.query(sql)
session.prompt(query)
session.prompt(query, { schema })
session.stream(query)
session.publish()
session.shareLink({ role, expiresInMs, maxViews, label })
```

## License

MIT
