npm package: @novala/sdk
Description: Official Node.js SDK for the Novala API — generate, deploy, and monitor AI-powered API integration flows.
Latest version: 0.1.0

# @novala/sdk

Official Node.js SDK for the Novala API — generate, deploy, and monitor AI-powered API integration flows.

## Installation

```bash
npm install @novala/sdk
```

## Quick Start

```ts
import { Novala } from "@novala/sdk";

const novala = new Novala({ secretKey: "sk_live_..." });

// Generate a flow from natural language
const job = await novala.generate({
  url: "https://api.stripe.com",
  intent: "sync new customers to my CRM",
});

// Wait for generation to complete
const result = await job.done();
console.log("Flow created:", result.result?.flowId);

// Deploy the flow
const deployment = await novala.deploy({ flowId: result.result!.flowId });
console.log("Deployed at:", deployment.deployedAt);

// Check execution results
const executions = await novala.executions.list({
  flowId: deployment.flowId,
  limit: 5,
});
console.log("Executions:", executions);
```

## Authentication

The SDK supports two key types:

| Key type | Prefix | Use case |
|----------|--------|----------|
| **Secret key** | `sk_live_*` | Server-side — full access |
| **Publishable key** | `pk_live_*` | Client-side — read-only access |

```ts
// Server-side (recommended)
const novala = new Novala({ secretKey: "sk_live_..." });

// Client-side
const novala = new Novala({ publishableKey: "pk_live_..." });
```

## Generation

Generate a flow from a target API URL and natural language intent:

```ts
const job = await novala.generate({
  url: "https://api.stripe.com",
  intent: "sync new customers to a webhook",
});

// Option 1: Await completion
const result = await job.done();

// Option 2: Poll with status updates
for await (const status of job.poll({ intervalMs: 1000, timeoutMs: 60000 })) {
  console.log(`${status.status} — ${status.progress}%`);
  if (status.status === "COMPLETED") {
    console.log("YAML:", status.result?.yaml);
  }
}

// Option 3: Real-time progress via WebSocket
job.onProgress((event) => {
  console.log(`${event.status}: ${event.message}`);
});
const final = await job.done();
```

## Flows

Manage generated flows:

```ts
// List all flows
const flows = await novala.flows.list();

// Get flow details
const flow = await novala.flows.get("flow-id");

// Deploy a flow
const result = await novala.deploy({ flowId: "flow-id" });

// Delete a flow
await novala.flows.delete("flow-id");
```

## Executions

Monitor flow execution history:

```ts
// List executions for a flow
const executions = await novala.executions.list({
  flowId: "flow-id",
  status: "failed",  // optional filter
  limit: 10,
  offset: 0,
});

// Get execution details (includes error info)
const execution = await novala.executions.get("execution-id");
if (execution.error) {
  console.error(`Failed at node ${execution.error.failedNodeId}: ${execution.error.message}`);
}
```

## Webhooks

Manage webhook subscriptions for flow events:

```ts
// List webhooks for a flow
const hooks = await novala.webhooks.list("flow-id");

// Create a webhook
const hook = await novala.webhooks.create({
  flowId: "flow-id",
  url: "https://example.com/webhook",
  events: ["flow.executed.success", "flow.executed.failure"],
});

// Update a webhook
await novala.webhooks.update(hook.id, { active: false });

// Delete a webhook
await novala.webhooks.delete(hook.id);
```

## Error Handling

The SDK throws typed errors for different failure scenarios:

| Error class | Status | When thrown |
|-------------|--------|------------|
| `AuthenticationError` | 401, 403 | Invalid or expired API key |
| `NotFoundError` | 404 | Resource doesn't exist |
| `ValidationError` | 422 | Invalid request parameters |
| `RateLimitError` | 429 | Too many requests (includes `retryAfterMs`) |
| `TimeoutError` | 408 | Request or poll timeout |
| `NovalaError` | * | Base class for all API errors |

```ts
import { RateLimitError, NotFoundError } from "@novala/sdk";

try {
  await novala.flows.get("non-existent");
} catch (err) {
  if (err instanceof NotFoundError) {
    console.log("Flow not found");
  } else if (err instanceof RateLimitError) {
    console.log(`Rate limited — retry after ${err.retryAfterMs}ms`);
  }
}
```

The transport layer automatically retries on 429 and 5xx errors (up to 3 attempts) with exponential backoff. When a `Retry-After` header is present, it is used as the retry delay.

## Configuration

```ts
const novala = new Novala({
  secretKey: "sk_live_...",
  baseUrl: "https://api.novala.ai",  // default
  timeout: 30000,                     // request timeout in ms (default: 30s)
});
```

## Requirements

- Node.js >= 18
- Works in both ESM and CommonJS environments