npm package: @prampta/sdk
Description: Official Node.js SDK for PRAMPTA — create, search, and manage AI prompts. Includes built-in MCP server for Claude, Cursor and other AI assistants.
Author: PRAMPTA Team
Latest version: 0.3.2

# @prampta/sdk

Official Node.js SDK for the PRAMPTA API — create, search, and manage AI prompts with automatic retry logic and TypeScript support.

## Features

- **TypeScript-first** with full type definitions
- **Automatic retries** with exponential backoff
- **Request cancellation** via AbortSignal
- **Rate limit handling** with intelligent retry
- **Zero dependencies** (uses native fetch)

## Installation

```bash
npm install @prampta/sdk
# or
pnpm add @prampta/sdk
# or
yarn add @prampta/sdk
```

## Quick Start

```typescript
import { Prampta } from '@prampta/sdk';

const prampta = new Prampta({
  apiKey: 'pk_xxxx-xx-xx-xx-xxxxxx', // Get at prampta.com/profile
});

// Create a prompt
const result = await prampta.create({
  content: 'Write a TypeScript function that validates email addresses...',
  title: 'Email Validator',
});
console.log('Created:', result.ppCode); // PP-3YGBM5V0HN-4

// Decode a prompt
const prompt = await prampta.decode('PP-3YGBM5V0HN-4');
console.log(prompt.content);

// Search prompts
const { prompts } = await prampta.search({
  query: 'typescript',
  category: 'development',
  limit: 10,
});
```

## API Reference

### Constructor

```typescript
new Prampta(config: PramptaConfig)
```

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `apiKey` | `string` | (required) | Your API key (starts with `pk_`) |
| `baseUrl` | `string` | `https://prampta.com` | API base URL |
| `timeoutMs` | `number` | `30000` | Request timeout in ms |
| `maxRetries` | `number` | `3` | Max retry attempts |

### Methods

#### `decode(code, options?)`

Get the full prompt content by PP code.

```typescript
const prompt = await prampta.decode('PP-3YGBM5V0HN-4');
// Returns: Prompt with content, media, metadata
```

#### `lookup(code, options?)`

Get prompt metadata without content (increments usage counter).

```typescript
const metadata = await prampta.lookup('PP-3YGBM5V0HN-4');
// Returns: PromptMetadata (no content field)
```

#### `search(searchOptions?, requestOptions?)`

Search the public prompt library.

```typescript
const result = await prampta.search({
  query: 'react hooks',
  category: 'development', // development, design, marketing, data, writing, business
  limit: 20,
  page: 1,
});
// Returns: { prompts, total, page, totalPages }
```

#### `create(options, requestOptions?)`

Create a new prompt.

```typescript
const result = await prampta.create({
  content: 'Your prompt content here (10-50,000 chars)',
  title: 'Optional title',
  media: {
    'img1': 'data:image/png;base64,...', // Optional media attachments
  },
});
// Returns: { ppCode, title, category, tags }
```

#### `myPrompts(options?)`

List your own prompts.

```typescript
const prompts = await prampta.myPrompts();
// Returns: Prompt[]
```

#### `register(ppCode, options?)`

Register an existing PP code to your account.

```typescript
const { registered, prompt } = await prampta.register('PP-3YGBM5V0HN-4');
```

#### `healthCheck()`

Check API connectivity and authentication.

```typescript
const health = await prampta.healthCheck();
// Returns: { healthy: boolean, latencyMs: number, authenticated: boolean }
```

### Request Cancellation

All methods accept an optional `signal` for cancellation:

```typescript
const controller = new AbortController();

// Cancel after 5 seconds
setTimeout(() => controller.abort(), 5000);

try {
  const prompt = await prampta.decode('PP-xxx', {
    signal: controller.signal,
  });
} catch (err) {
  if (err.message === 'Request was cancelled') {
    console.log('Request cancelled');
  }
}
```

### Error Handling

```typescript
import { Prampta, PramptaError } from '@prampta/sdk';

try {
  const prompt = await prampta.decode('PP-invalid');
} catch (err) {
  if (err instanceof PramptaError) {
    console.error(`API error ${err.status}: ${err.message}`);
    
    if (err.status === 404) {
      console.log('Prompt not found');
    } else if (err.status === 429) {
      console.log('Rate limited, try again later');
    } else if (err.status === 401) {
      console.log('Invalid API key');
    }
  }
}
```

## Types

```typescript
interface Prompt {
  id: string;
  ppCode: string;
  title: string;
  content: string;
  category: string;
  tags: string[];
  authorName: string | null;
  uses: number;
  likes: number;
  visibility: 'public' | 'private';
  createdAt: number;
  media?: Record<string, string>;
}

interface CreateOptions {
  content: string;     // 10-50,000 characters
  title?: string;      // Max 200 characters
  media?: Record<string, string>; // Base64 data URLs
}

interface SearchOptions {
  query?: string;
  category?: 'development' | 'design' | 'marketing' | 'data' | 'writing' | 'business';
  limit?: number;  // 1-100
  page?: number;
}
```

## Examples

### With Express.js

```typescript
import express from 'express';
import { Prampta } from '@prampta/sdk';

const app = express();
const prampta = new Prampta({ apiKey: process.env.PRAMPTA_API_KEY! });

app.get('/prompt/:code', async (req, res) => {
  try {
    const prompt = await prampta.decode(req.params.code);
    res.json(prompt);
  } catch (err) {
    res.status(err.status || 500).json({ error: err.message });
  }
});
```

### With Next.js API Routes

```typescript
// app/api/prompts/route.ts
import { NextResponse } from 'next/server';
import { Prampta } from '@prampta/sdk';

const prampta = new Prampta({ apiKey: process.env.PRAMPTA_API_KEY! });

export async function GET(request: Request) {
  const { searchParams } = new URL(request.url);
  const query = searchParams.get('q') || '';
  
  const result = await prampta.search({ query });
  return NextResponse.json(result);
}
```

### Batch Operations

```typescript
const codes = ['PP-xxx', 'PP-yyy', 'PP-zzz'];

// Parallel fetching with error handling
const results = await Promise.allSettled(
  codes.map(code => prampta.decode(code))
);

const prompts = results
  .filter((r): r is PromiseFulfilledResult<Prompt> => r.status === 'fulfilled')
  .map(r => r.value);
```

## Rate Limits

| Limit | Value |
|-------|-------|
| Requests per minute | 200 |
| Requests per day | 5,000 |
| Max prompt size | 50,000 chars |
| Max media per prompt | 8 files |
| Max media size | 2MB per file |

The SDK automatically handles rate limiting with retries.

## License

MIT