npm package: @raspect/workflow-sdk
Description: Node.js SDK for Inspectica Workflow Server - Activity worker implementation
Author: Inspectica Team
Latest version: 1.5.0

# @inspectica/workflow-sdk

Node.js SDK for Inspectica Workflow Server - Execute workflows and activities.

## Installation

```bash
npm install @inspectica/workflow-sdk
```

## Quick Start

```typescript
import { Worker, workflow, activity } from '@inspectica/workflow-sdk';

// Define an activity
const sayHello = activity.defn(async (input: { name: string }) => {
  return { message: `Hello, ${input.name}!` };
});

// Define a workflow
@workflow.defn
class HelloWorldWorkflow {
  @workflow.run
  async run(input: { name: string }) {
    const result = await workflow.executeActivity(sayHello, input);
    return result;
  }
}

// Create and start the worker
const worker = new Worker({
  serverUrl: 'https://workflow.example.com',
  apiKey: 'wk_your_api_key_here',
});

worker.register({
  workflows: [HelloWorldWorkflow],
  activities: [sayHello],
});

await worker.run();
```

## Configuration

### Worker Configuration

```typescript
const worker = new Worker({
  serverUrl: 'https://workflow.example.com',
  apiKey: 'wk_abc123...',
  groupId: 'my-consumer-group',        // optional, defaults to worker-id based
  maxConcurrentWorkflows: 10,          // optional, default 10
});
```

## Activities

Activities are the building blocks of workflows. They represent individual units of work.

```typescript
import { activity } from '@inspectica/workflow-sdk';

// Simple activity
const processData = activity.defn(async (input: { data: number[] }) => {
  const sum = input.data.reduce((a, b) => a + b, 0);
  return { sum };
});

// Activity with custom name
const myActivity = activity.defn(
  async (input: { value: string }) => {
    return { processed: input.value.toUpperCase() };
  },
  'custom_activity_name'  // optional custom name
);
```

## Workflows

Workflows orchestrate activities and define the business logic.

```typescript
import { workflow, activity } from '@inspectica/workflow-sdk';

const step1 = activity.defn(async (input: { data: string }) => {
  return { result: input.data + '_step1' };
});

const step2 = activity.defn(async (input: { data: string }) => {
  return { result: input.data + '_step2' };
});

@workflow.defn
class MyWorkflow {
  @workflow.run
  async run(input: { initialData: string }) {
    // Execute activities sequentially
    const result1 = await workflow.executeActivity(step1, { data: input.initialData });
    const result2 = await workflow.executeActivity(step2, { data: result1.result });
    
    return { finalResult: result2.result };
  }
}
```

### Accessing Workflow Context

You can access the workflow context to get metadata (like access tokens):

```typescript
import { workflow, getCurrentContext } from '@inspectica/workflow-sdk';

@workflow.defn
class AuthenticatedWorkflow {
  @workflow.run
  async run(input: { projectId: string }) {
    const ctx = getCurrentContext();
    
    // Access metadata passed from the workflow submission
    const accessToken = ctx.metadata.access_token;
    const workflowId = ctx.workflowId;
    
    // Use the token for authorization checks
    // ...
    
    return { success: true };
  }
}
```

### Cross-Worker Activity Execution

You can call activities registered on other workers by using the activity name as a string:

```typescript
@workflow.defn
class CrossWorkerWorkflow {
  @workflow.run
  async run(input: { data: string }) {
    // Call an activity on another worker by name
    const result = await workflow.executeActivity(
      'remote_activity_name',  // Activity registered on another worker
      { data: input.data },
      120000  // timeout in ms
    );
    
    return result;
  }
}
```

## API Reference

### Worker

```typescript
class Worker {
  constructor(config: WorkerConfig);
  
  // Register workflows and activities
  register(options: {
    workflows?: WorkflowClass[];
    activities?: ActivityHandler[];
  }): void;
  
  // Start the worker (blocking)
  run(): Promise<void>;
  
  // Stop the worker gracefully
  stop(): Promise<void>;
}

interface WorkerConfig {
  serverUrl: string;
  apiKey: string;
  groupId?: string;
  maxConcurrentWorkflows?: number;
}
```

### Activity

```typescript
// Define an activity
activity.defn<TInput, TOutput>(
  fn: (input: TInput) => Promise<TOutput> | TOutput,
  activityName?: string
): ActivityHandler<TInput, TOutput>;

// Get activity name
activity.getActivityName(fn: ActivityHandler | string): string;

// Check if function is an activity
activity.isActivity(fn: unknown): boolean;
```

### Workflow

```typescript
// Class decorator to mark as workflow
@workflow.defn
class MyWorkflow { ... }

// Method decorator to mark as entry point
@workflow.run
async run(input: any) { ... }

// Execute an activity within a workflow
workflow.executeActivity<TInput, TOutput>(
  activity: ActivityHandler<TInput, TOutput> | string,
  inputData?: TInput,
  startToCloseTimeoutMs?: number  // default: 60000
): Promise<TOutput>;

// Get current workflow context
getCurrentContext(): WorkflowContext;
```

### WorkflowContext

```typescript
class WorkflowContext {
  readonly workflowId: string;
  readonly metadata: Record<string, unknown>;
  readonly activityResults: unknown[];
  
  executeActivity<TInput, TOutput>(
    activity: ActivityHandler<TInput, TOutput> | string,
    inputData?: TInput,
    startToCloseTimeoutMs?: number
  ): Promise<TOutput>;
}
```

## Features

- **Workflow Execution**: Define and execute complex workflows with multiple activities
- **Activity Replay**: Automatic replay of completed activities on workflow resume
- **Cross-Worker Routing**: Execute activities on different workers via the server
- **Concurrency Control**: Limit concurrent workflow executions to prevent OOM
- **AWS MSK IAM Support**: Built-in support for AWS MSK with IAM authentication
- **Graceful Shutdown**: Proper cleanup on SIGINT/SIGTERM signals
- **Heartbeat**: Automatic heartbeat to keep worker connection alive

## License

MIT