# Diaphora TypeScript SDK

TypeScript client library for the [Diaphora](/content/site-root.html) API.

**Supported Node.js versions**: 20.x, 22.x

## Installation

```
npm install diaphora-typescript
```

## Authentication

The Diaphora client needs your Diaphora credentials. You can either pass these directly to the constructor or via environment variables.

```
import { BasicAuthenticator } from 'diaphora-typescript';

const auth = new BasicAuthenticator('user@example.com', 'your-password');
```

Credentials can also be provided via environment variables:

```
DIAPHORA_USERNAME=user@example.com
DIAPHORA_PASSWORD=your-password
```

To use a custom auth scheme, extend `DiaphoraAuthenticator`:

```
import { DiaphoraAuthenticator } from 'diaphora-typescript';

class MyAuthenticator extends DiaphoraAuthenticator {
  token(): string | Promise<string> {
    return 'my-session-token';
  }
}
```

## Setup

```
import { FragsStoreClient, FragsRouterClient } from 'diaphora-typescript';

const store = new FragsStoreClient(auth);
const router = new FragsRouterClient(auth);
```

| Client | Description |
| --- | --- |
| `store` | Plan and result management |
| `router` | Plan execution and MCP tools |

## Quickstart

### Search for plans

```javascript
// namespace is one of: 'all' | 'diaphora' | 'barndoor' | 'none'
const plans = await store.searchPlans(undefined, undefined, 'diaphora');
```

### Show a plan

```javascript
const plan = await store.showPlan(plans[0]?.id);
console.log(plan.name, plan.description);
```

### Create a plan

```javascript
const newPlan = await store.createPlan({
  name: 'Daily Summary',
  description: 'Summarizes activity from the past 24 hours',
  visibility: 'organization',
  labels: ['summary', 'daily'],
  text: '<plan definition>',
});
```

### Search results for a plan

```javascript
const results = await store.searchResults(plan.id, undefined, 'success');
```

### Run a plan

```javascript
const response = await router.runPlan(plan.id, {
  parameters: { animal_type: 'feline' },
});
```

### Stream a plan execution

```javascript
import type { StreamEvent } from 'diaphora-typescript';

await router.streamPlan(
  plan.id,
  { parameters: { animal_type: 'feline' } },
  (event: StreamEvent) => {
    if (event.event === 'start') {
      console.log(`[${event.component}] starting...`);
    } else if (event.event === 'end') {
      console.log(`[${event.component}] done`);
    } else if (event.event === 'result') {
      const content = event.content as Record<string, unknown>;
      console.log(content.document);
    }
  }
);
```

## store (FragsStoreClient)

### Plans

| Method | Description |
| --- | --- |
| [`searchPlans`](/content/docs/sdk/typescript#searchplans/index.html) | Search plans. `namespace` is one of `'all'`, `'diaphora'`, `'barndoor'`, `'none'` |
| [`showPlan`](/content/docs/sdk/typescript#showplan/index.html) | Get plan details |
| [`createPlan`](/content/docs/sdk/typescript#createplan/index.html) | Create a plan |
| [`updatePlan`](/content/docs/sdk/typescript#updateplan/index.html) | Update a plan |
| [`deletePlan`](/content/docs/sdk/typescript#deleteplan/index.html) | Delete a plan |
| [`listPlanLabels`](/content/docs/sdk/typescript#listplanlabels/index.html) | List all labels used across plans |

#### `searchPlans`

Search plans visible to the authenticated user, with optional filtering and sorting.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `label` | `string[]` | No | Filter to plans tagged with any of the given labels |
| `search` | `string` | No | Full-text search string |
| `namespace` | `'all' | 'diaphora' | 'barndoor' | 'none'` | No | Scope of plans to include |
| `limit` | `number` | No | Maximum number of results to return |
| `offset` | `number` | No | Number of results to skip (for pagination) |
| `orderBy` | `'name' | 'created_at' | 'updated_at'` | No | Field to sort by |
| `orderMode` | `'ASC' | 'DESC'` | No | Sort direction |

**Example**

```javascript
const plans = await store.searchPlans(['daily'], 'summary', 'diaphora', 10, 0, 'created_at', 'DESC');
```

#### `showPlan`

Get full details for a single plan, including its text and parameter definitions.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | Yes | UUID of the plan |

**Example**

```javascript
const plan = await store.showPlan('plan-uuid');
console.log(plan.name, plan.text);
```

#### `createPlan`

Create a new plan.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body.name` | `string` | Yes | Display name for the plan |
| `body.description` | `string` | Yes | Human-readable description |
| `body.visibility` | `'user' | 'organization' | 'namespace'` | Yes | Who can see the plan |
| `body.labels` | `string[]` | Yes | Labels to tag the plan with |
| `body.text` | `string` | Yes | The plan definition (Frags syntax) |
| `body.namespace` | `string` | No | Namespace to publish to (required when `visibility` is `'namespace'`) |
| `body.document_template` | `string` | No | Go template for the output document |

**Example**

```javascript
const plan = await store.createPlan({
  name: 'Daily Summary',
  description: 'Summarises activity from the past 24 hours',
  visibility: 'organization',
  labels: ['summary', 'daily'],
  text: '<plan definition>',
});
```

#### `updatePlan`

Replace all fields of an existing plan.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | Yes | UUID of the plan to update |
| `body.name` | `string` | Yes | Display name for the plan |
| `body.description` | `string` | Yes | Human-readable description |
| `body.visibility` | `'user' | 'organization' | 'namespace'` | Yes | Who can see the plan |
| `body.labels` | `string[]` | Yes | Labels to tag the plan with |
| `body.text` | `string` | Yes | The plan definition (Frags syntax) |
| `body.namespace` | `string` | No | Namespace to publish to |
| `body.document_template` | `string` | No | Go template for the output document |

**Example**

```javascript
await store.updatePlan('plan-uuid', {
  name: 'Updated Summary',
  description: 'Now covers the past 48 hours',
  visibility: 'organization',
  labels: ['summary', 'daily'],
  text: '<updated plan definition>',
});
```

#### `deletePlan`

Delete a plan by ID. Returns `void`.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | Yes | UUID of the plan to delete |

**Example**

```javascript
await store.deletePlan('plan-uuid');
```

#### `listPlanLabels`

List all unique labels used across plans in the organization.

**Example**

```javascript
const labels = await store.listPlanLabels();
console.log(labels); // ['daily', 'summary', 'report']
```

### Results

| Method | Description |
| --- | --- |
| [`searchResults`](/content/docs/sdk/typescript#searchresults/index.html) | Search results. `status` is `'success'` or `'error'` |
| [`showResults`](/content/docs/sdk/typescript#showresults/index.html) | Get result details |
| [`createResults`](/content/docs/sdk/typescript#createresults/index.html) | Create a result |
| [`deleteResults`](/content/docs/sdk/typescript#deleteresults/index.html) | Delete a result |
| [`listResultStats`](/content/docs/sdk/typescript#listresultstats/index.html) | Get result statistics |

#### `searchResults`

Search execution results, optionally filtering by plan, status, or date range.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | No | Filter to results for a specific plan UUID |
| `search` | `string` | No | Full-text search string |
| `status` | `'success' | 'error'` | No | Filter by execution status |
| `limit` | `number` | No | Maximum number of results to return |
| `offset` | `number` | No | Number of results to skip (for pagination) |
| `start` | `Date` | No | Return only results created at or after this time |
| `end` | `Date` | No | Return only results created at or before this time |

**Example**

```javascript
const results = await store.searchResults(
  plan.id,
  undefined,
  'success',
  20,
  0,
  new Date('2025-01-01'),
  new Date('2025-02-01'),
);
```

#### `showResults`

Get full details for a single result, including the execution data.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `resultsId` | `string` | Yes | UUID of the result |

**Example**

```javascript
const result = await store.showResults('result-uuid');
console.log(result.data.document);
```

#### `createResults`

Store a result record manually, useful for persisting results generated outside the router.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body.plan_id` | `string` | Yes | UUID of the plan this result belongs to |
| `body.plan_name` | `string` | Yes | Name of the plan at the time of execution |
| `body.data` | `object` | Yes | Execution response body (`result`, `document`, `warnings`, etc.) |
| `body.id` | `string` | No | Optional UUID to assign to this result |

**Example**

```javascript
const result = await store.createResults({
  plan_id: 'plan-uuid',
  plan_name: 'Daily Summary',
  data: {
    result: {},
    document: 'Generated output here',
    warnings: [],
  },
});
```

#### `deleteResults`

Delete a result by ID. Returns `void`.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `resultsId` | `string` | Yes | UUID of the result to delete |

**Example**

```javascript
await store.deleteResults('result-uuid');
```

#### `listResultStats`

Get per-result statistics, optionally filtered to a date range.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `start` | `Date` | No | Return only stats for results created at or after this time |
| `end` | `Date` | No | Return only stats for results created at or before this time |

**Example**

```javascript
const stats = await store.listResultStats(
  new Date('2025-01-01'),
  new Date('2025-02-01'),
);
```

### Public Links

| Method | Description |
| --- | --- |
| [`listPublicLinks`](/content/docs/sdk/typescript#listpubliclinks/index.html) | List public links for a result |
| [`createPublicLink`](/content/docs/sdk/typescript#createpubliclink/index.html) | Create a public link. `expires_in` accepts values like `'7d'` or `'24h'` |
| [`deletePublicLink`](/content/docs/sdk/typescript#deletepubliclink/index.html) | Delete a public link |
| [`showResultPublicLink`](/content/docs/sdk/typescript#showresultpubliclink/index.html) | Fetch a result via public link (no auth required) |

#### `listPublicLinks`

List all public share links for a result.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `resultsId` | `string` | Yes | UUID of the result |

**Example**

```javascript
const links = await store.listPublicLinks('result-uuid');
```

#### `createPublicLink`

Create a public share link for a result with an expiry duration and a display label.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `resultsId` | `string` | Yes | UUID of the result |
| `body.expires_in` | `string` | Yes | How long until the link expires, e.g. `'7d'` or `'24h'` |
| `body.label` | `string` | Yes | Human-readable label for this link |

**Example**

```javascript
const link = await store.createPublicLink('result-uuid', {
  expires_in: '7d',
  label: 'Share with client',
});
console.log(link.id, link.expires_at);
```

#### `deletePublicLink`

Revoke a public link. Returns `void`.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `resultsId` | `string` | Yes | UUID of the result |
| `publicLinkId` | `string` | Yes | UUID of the public link to revoke |

**Example**

```javascript
await store.deletePublicLink('result-uuid', 'link-uuid');
```

#### `showResultPublicLink`

Fetch result details via a public link — no authentication required.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `publicLinkId` | `string` | Yes | UUID of the public link |

**Example**

```javascript
const result = await store.showResultPublicLink('link-uuid');
console.log(result.data.document);
```

### Tools & Schema

| Method | Description |
| --- | --- |
| [`listTools`](/content/docs/sdk/typescript#listtools/index.html) | List available tools |
| [`showTool`](/content/docs/sdk/typescript#showtool/index.html) | Get tool details |
| [`showDefaultTools`](/content/docs/sdk/typescript#showdefaulttools/index.html) | Get default tools |
| [`createTool`](/content/docs/sdk/typescript#createtool/index.html) | Create a tool |
| [`updateTool`](/content/docs/sdk/typescript#updatetool/index.html) | Update a tool |
| [`showMcpServerDetails`](/content/docs/sdk/typescript#showmcpserverdetails/index.html) | Get MCP server details for a tool |
| [`showApiCPServerDetails`](/content/docs/sdk/typescript#showapicpserverdetails/index.html) | Get API CP server details for a tool |
| [`getFragsSchema`](/content/docs/sdk/typescript#getfragsschema/index.html) | Get the Frags JSON schema |
| [`getFragsSkill`](/content/docs/sdk/typescript#getfragsskill/index.html) | Get the Frags skill definition |

#### `listTools`

List all tool configurations available to the organization.

**Example**

```javascript
const tools = await store.listTools();
```

#### `showTool`

Get full details of a tool configuration. Facet parameters filter which MCP servers, collections, and API CPs are returned.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `toolId` | `string` | Yes | UUID of the tool |
| `facetMcps` | `string[]` | No | Only include these MCP server IDs |
| `facetCollections` | `string[]` | No | Only include these collection names |
| `facetApiCps` | `string[]` | No | Only include these API CP IDs |

**Example**

```javascript
const tool = await store.showTool('tool-uuid');
console.log(tool.mcp_servers);
```

#### `showDefaultTools`

Get the default tool configuration. Facet parameters work the same as [`showTool`](/content/docs/sdk/typescript#showtool/index.html).

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `facetMcps` | `string[]` | No | Only include these MCP server IDs |
| `facetCollections` | `string[]` | No | Only include these collection names |
| `facetApiCps` | `string[]` | No | Only include these API CP IDs |

**Example**

```javascript
const defaults = await store.showDefaultTools();
```

#### `createTool`

Create a new tool configuration.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body.name` | `string` | Yes | Display name for the tool |
| `body.default` | `boolean` | Yes | Whether this is the default tool configuration |
| `body.mcp_servers` | `mcp_server[]` | Yes | MCP servers to include |
| `body.collections` | `collection[]` | Yes | Collections to include |
| `body.api_cps` | `apicp_config[]` | Yes | API CP servers to include |

**Example**

```javascript
const tool = await store.createTool({
  name: 'My Tool',
  default: false,
  mcp_servers: [],
  collections: [],
  api_cps: [],
});
```

#### `updateTool`

Replace all fields of an existing tool configuration.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `toolId` | `string` | Yes | UUID of the tool to update |
| `body.name` | `string` | Yes | Display name for the tool |
| `body.default` | `boolean` | Yes | Whether this is the default tool configuration |
| `body.mcp_servers` | `mcp_server[]` | Yes | MCP servers to include |
| `body.collections` | `collection[]` | Yes | Collections to include |
| `body.api_cps` | `apicp_config[]` | Yes | API CP servers to include |

**Example**

```javascript
await store.updateTool('tool-uuid', {
  name: 'Updated Tool',
  default: true,
  mcp_servers: [],
  collections: [],
  api_cps: [],
});
```

#### `showMcpServerDetails`

Get the configuration for a specific MCP server within a tool.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `toolId` | `string` | Yes | UUID of the tool |
| `serverId` | `string` | Yes | UUID of the MCP server |

**Example**

```javascript
const server = await store.showMcpServerDetails('tool-uuid', 'server-uuid');
console.log(server.url, server.authentication_method);
```

#### `showApiCPServerDetails`

Get the configuration for a specific API CP server within a tool.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `toolId` | `string` | Yes | UUID of the tool |
| `serverId` | `string` | Yes | UUID of the API CP server |

**Example**

```javascript
const server = await store.showApiCPServerDetails('tool-uuid', 'server-uuid');
```

#### `getFragsSchema`

Fetch the Frags JSON schema used to validate plan definitions.

**Example**

```javascript
const schema = await store.getFragsSchema();
```

#### `getFragsSkill`

Fetch the Frags skill definition as a markdown string, suitable for use as an LLM system prompt.

**Example**

```javascript
const skill = await store.getFragsSkill();
```

## router (FragsRouterClient)

### Plan Execution

| Method | Description |
| --- | --- |
| [`runPlan`](/content/docs/sdk/typescript#runplan/index.html) | Execute a plan synchronously |
| [`streamPlan`](/content/docs/sdk/typescript#streamplan/index.html) | Execute a plan and receive SSE events via callback. Returns the final result. |

`streamPlan` delivers `StreamEvent` objects to the callback:

| `event.event` | Additional fields | Description |
| --- | --- | --- |
| `'start'` | `component`, `session` | A component started |
| `'end'` | `component` | A component finished |
| `'result'` | `content` | Result payload — `content.document` holds the output text |

#### `runPlan`

Execute a plan synchronously and return the result once complete.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | Yes | UUID of the plan to execute |
| `body.parameters` | `Record<string, unknown>` | No | Input parameters for the plan (defaults to `{}`) |
| `body.auth_overrides` | `auth_override[]` | No | Per-execution token overrides for MCP/API CP servers |
| `body.resources` | `Record<string, string>` | No | Named resource bindings for the execution |

**Example**

```javascript
const result = await router.runPlan('plan-uuid', {
  parameters: { animal_type: 'feline' },
});
console.log(result.document);
```

#### `streamPlan`

Execute a plan and receive `StreamEvent` objects via a callback as each component starts and finishes. Returns the final result content once the stream closes, or `undefined` if the stream ends without a `result` event.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | Yes | UUID of the plan to execute |
| `body.parameters` | `Record<string, unknown>` | No | Input parameters for the plan (defaults to `{}`) |
| `body.auth_overrides` | `auth_override[]` | No | Per-execution token overrides for MCP/API CP servers |
| `body.resources` | `Record<string, string>` | No | Named resource bindings for the execution |
| `onEvent` | `(event: StreamEvent) => void` | No | Callback invoked for each SSE event |

Unlike `runPlan`, the returned promise can resolve to `undefined` (the stream may end without ever emitting a `result` event) — always guard with `?.` or a null check.

**Example**

```javascript
import type { StreamEvent } from 'diaphora-typescript';

const result = await router.streamPlan(
  'plan-uuid',
  { parameters: { animal_type: 'feline' } },
  (event: StreamEvent) => {
    if (event.event === 'start') {
      console.log(`[${event.component}] starting...`);
    } else if (event.event === 'result') {
      const content = event.content as Record<string, unknown>;
      console.log(content.document);
    }
  },
);
console.log(result?.document);
```

### MCP Tools

| Method | Description |
| --- | --- |
| [`checkPlanMcpRequirements`](/content/docs/sdk/typescript#checkplanmcprequirements/index.html) | Check which MCP servers a plan needs and their auth status |
| [`refreshPlanMcpRequirements`](/content/docs/sdk/typescript#refreshplanmcprequirements/index.html) | Force-refresh MCP requirement status |
| [`checkToolMcpRequirements`](/content/docs/sdk/typescript#checktoolmcprequirements/index.html) | Check global MCP requirements |
| [`listToolCommands`](/content/docs/sdk/typescript#listtoolcommands/index.html) | List commands on an MCP server |
| [`callToolCommand`](/content/docs/sdk/typescript#calltoolcommand/index.html) | Execute an MCP command |
| [`listMcpAuthCache`](/content/docs/sdk/typescript#listmcpauthcache/index.html) | List cached MCP OAuth tokens |
| [`deleteMcpAuthCache`](/content/docs/sdk/typescript#deletemcpauthcache/index.html) | Revoke a cached MCP token |
| [`mcpCallback`](/content/docs/sdk/typescript#mcpcallback/index.html) | Handle an OAuth redirect callback |
| [`renderTemplate`](/content/docs/sdk/typescript#rendertemplate/index.html) | Render a template |

#### `checkPlanMcpRequirements`

Check which MCP and API CP servers a plan requires and whether they are currently authenticated.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | Yes | UUID of the plan |

**Example**

```javascript
const requirements = await router.checkPlanMcpRequirements('plan-uuid');
for (const req of requirements) {
  console.log(req.name, req.status); // 'ready' or 'not_ready'
}
```

#### `refreshPlanMcpRequirements`

Force-refresh the MCP requirement status for a plan, clearing any cached auth state.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `planId` | `string` | Yes | UUID of the plan |

**Example**

```javascript
await router.refreshPlanMcpRequirements('plan-uuid');
```

#### `checkToolMcpRequirements`

Check the MCP and API CP authentication status across all tool configurations globally.

**Example**

```javascript
const requirements = await router.checkToolMcpRequirements();
```

#### `listToolCommands`

List all available commands on a specific MCP server within a tool configuration.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `toolsId` | `string` | Yes | UUID of the tool configuration |
| `serverId` | `string` | Yes | UUID of the MCP server |

**Example**

```javascript
const commands = await router.listToolCommands('tool-uuid', 'server-uuid');
for (const cmd of commands) {
  console.log(cmd.name, cmd.description);
}
```

#### `callToolCommand`

Execute a named command on an MCP server and return the result.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `toolsId` | `string` | Yes | UUID of the tool configuration |
| `serverId` | `string` | Yes | UUID of the MCP server |
| `commandName` | `string` | Yes | Name of the command to execute |
| `body` | `Record<string, unknown>` | Yes | Input arguments for the command |

**Example**

```javascript
const result = await router.callToolCommand(
  'tool-uuid',
  'server-uuid',
  'list_issues',
  { repo: 'my-org/my-repo' },
);
```

#### `listMcpAuthCache`

List currently cached MCP OAuth tokens.

**Example**

```javascript
const cache = await router.listMcpAuthCache();
for (const entry of cache) {
  console.log(entry.id, entry.expiry);
}
```

#### `deleteMcpAuthCache`

Revoke a cached MCP OAuth token. Returns `void`.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `cacheId` | `string` | Yes | ID of the cache entry to revoke |

**Example**

```javascript
await router.deleteMcpAuthCache('cache-id');
```

#### `mcpCallback`

Handle the OAuth redirect callback after a user completes MCP authentication in their browser. Called automatically by the OAuth flow — you typically do not need to call this directly.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `state` | `string` | Yes | OAuth state parameter from the redirect URL |
| `code` | `string` | Yes | Authorization code from the redirect URL |

**Example**

```javascript
await router.mcpCallback(stateParam, codeParam);
```

#### `renderTemplate`

Render a Go template string with a provided scope object and return the result as a string.

**Parameters**

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `body.template` | `string` | Yes | Go template string, e.g. `'Hello {{ .name }}!'` |
| `body.scope` | `Record<string, unknown>` | Yes | Variables available within the template |

**Example**

```javascript
const output = await router.renderTemplate({
  template: 'Hello {{ .name }}!',
  scope: { name: 'World' },
});
console.log(output); // 'Hello World!'
```
