npm.io
1.0.0 • Published 6 months ago

@flink-app/management-actions-plugin

Licence
MIT
Version
1.0.0
Deps
3
Size
47 kB
Vulns
0
Weekly
0

A Flink management API module that enables you to create and execute custom actions through the management API. This plugin integrates with @flink-app/management-api-plugin to expose server-side actions that can be triggered via HTTP requests.

Features

  • Define custom server-side actions with arguments
  • Execute actions through the management API
  • Type-safe argument handling
  • Built-in UI support for management interfaces
  • Flexible response handling with success/error states
  • List all available actions via API

Prerequisites

This plugin requires @flink-app/management-api-plugin to be installed and configured in your Flink application.

npm install @flink-app/management-api-plugin

Installation

npm install @flink-app/management-actions-plugin

Usage

Basic Setup
import { FlinkApp } from "@flink-app/flink";
import { managementApiPlugin } from "@flink-app/management-api-plugin";
import {
  GetManagementModule,
  ActionArugmentType,
  ActionReturnStatus,
} from "@flink-app/management-actions-plugin";

const actionsModule = GetManagementModule({
  ui: true,
  uiSettings: {
    title: "Actions",
  },
  actions: [
    {
      id: "hello-world",
      description: "Greets you with a personalized message",
      arguments: [
        {
          id: "name",
          type: ActionArugmentType.text,
          required: true,
        },
      ],
      async handler(ctx, args) {
        return {
          data: {
            message: "Hello " + args.name,
          },
          status: ActionReturnStatus.success,
        };
      },
    },
  ],
});

function start() {
  new FlinkApp<AppContext>({
    name: "My app",
    plugins: [
      managementApiPlugin({
        token: "SECRET_TOKEN",
        jwtSecret: "JWT_SECRET",
        modules: [actionsModule],
      }),
    ],
  }).start();
}

Action Definition

Each action requires the following properties:

Action Interface
interface Action {
  id: string; // Unique identifier for the action
  description?: string; // Human-readable description
  arguments: ActionArguments[]; // Array of input arguments
  handler: (ctx: FlinkContext<any>, args: ActionArgumentsValues) => Promise<ActionResponse>;
}
Action Arguments
interface ActionArguments {
  id: string; // Argument identifier
  required: boolean; // Whether the argument is required
  type: ActionArugmentType; // Argument type
  default?: string; // Optional default value
}

enum ActionArugmentType {
  text = "TEXT",
}
Action Response
interface ActionResponse {
  status: ActionReturnStatus; // SUCCESS or ERROR
  error?: string; // Error message (if status is ERROR)
  data?: {
    [key: string]: any; // Response data (if status is SUCCESS)
  };
}

enum ActionReturnStatus {
  success = "SUCCESS",
  error = "ERROR",
}

API Endpoints

The plugin exposes two endpoints for each actions module:

List Actions
GET /managementapi/{pluginId}

Returns a list of all available actions with their configurations.

Response:

[
  {
    "id": "hello-world",
    "description": "Greets you with a personalized message",
    "arguments": [
      {
        "id": "name",
        "type": "TEXT",
        "required": true
      }
    ]
  }
]
Execute Action
POST /managementapi/{pluginId}/{actionId}

Executes a specific action with provided arguments.

Headers:

management-token: YOUR_TOKEN_OR_JWT

Request Body:

{
  "name": "World"
}

Response:

{
  "status": "SUCCESS",
  "data": {
    "message": "Hello World"
  }
}

Advanced Examples

Action with Multiple Arguments
{
  id: "create-user",
  description: "Creates a new user in the system",
  arguments: [
    {
      id: "username",
      type: ActionArugmentType.text,
      required: true,
    },
    {
      id: "email",
      type: ActionArugmentType.text,
      required: true,
    },
    {
      id: "role",
      type: ActionArugmentType.text,
      required: false,
      default: "user",
    },
  ],
  async handler(ctx, args) {
    try {
      const user = await ctx.repos.userRepo.create({
        username: args.username,
        email: args.email,
        role: args.role,
      });

      return {
        status: ActionReturnStatus.success,
        data: { userId: user._id },
      };
    } catch (error) {
      return {
        status: ActionReturnStatus.error,
        error: error.message,
      };
    }
  },
}
Action with Database Access
{
  id: "cleanup-old-records",
  description: "Removes records older than 30 days",
  arguments: [],
  async handler(ctx, args) {
    try {
      const cutoffDate = new Date();
      cutoffDate.setDate(cutoffDate.getDate() - 30);

      const result = await ctx.repos.recordRepo.deleteMany({
        createdAt: { $lt: cutoffDate },
      });

      return {
        status: ActionReturnStatus.success,
        data: {
          deletedCount: result.deletedCount,
          message: `Removed ${result.deletedCount} old records`,
        },
      };
    } catch (error) {
      return {
        status: ActionReturnStatus.error,
        error: `Failed to cleanup records: ${error.message}`,
      };
    }
  },
}
Action with External API Call
{
  id: "sync-data",
  description: "Syncs data from external service",
  arguments: [
    {
      id: "service",
      type: ActionArugmentType.text,
      required: true,
    },
  ],
  async handler(ctx, args) {
    try {
      const response = await fetch(`https://api.example.com/${args.service}`);
      const data = await response.json();

      // Process and store data
      await ctx.repos.dataRepo.create(data);

      return {
        status: ActionReturnStatus.success,
        data: {
          recordsImported: data.length,
          service: args.service,
        },
      };
    } catch (error) {
      return {
        status: ActionReturnStatus.error,
        error: `Sync failed: ${error.message}`,
      };
    }
  },
}

Configuration Options

GetManagementModule Options
interface GetManagementModuleConfig {
  pluginId?: string; // Custom plugin ID (defaults to "managementActionsApi")
  ui: boolean; // Enable UI features
  uiSettings?: {
    title: string; // Display title in management UI
  };
  actions: Action[]; // Array of actions to register
}

Context Access

Action handlers receive the full Flink context, providing access to:

  • ctx.repos - All registered repositories
  • ctx.db - MongoDB database connection
  • ctx.plugins - All plugin contexts
  • Any other context properties from your application

Security

All action endpoints are protected by the management API authentication system. Ensure you:

  • Use the management token header for all requests
  • Validate and sanitize action arguments
  • Implement proper error handling
  • Avoid exposing sensitive data in responses
  • Log action executions for audit purposes

Testing Actions

You can test your actions using curl or any HTTP client:

# Get list of actions
curl 'https://your-api.com/managementapi/managementActionsApi' \
  -H 'management-token: YOUR_TOKEN'

# Execute an action
curl -X POST 'https://your-api.com/managementapi/managementActionsApi/hello-world' \
  -H 'management-token: YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"name":"World"}'

TypeScript Support

The plugin is written in TypeScript and provides full type definitions for all interfaces and enums.

Error Handling

Always return proper error responses from action handlers:

async handler(ctx, args) {
  try {
    // Your action logic
    return {
      status: ActionReturnStatus.success,
      data: { /* your data */ },
    };
  } catch (error) {
    return {
      status: ActionReturnStatus.error,
      error: error instanceof Error ? error.message : "Unknown error",
    };
  }
}

License

MIT