Files
actual/packages/plugins-core-sync-server/README.md
lelemm 605206d2f7 feat: Integrate plugin-based bank sync providers
- Add plugin bank sync providers to CreateAccountModal alongside existing providers
- Extend SelectLinkedAccountsModal to handle plugin accounts with unified interface
- Implement backend API handlers: bank-sync-providers-list, bank-sync-accounts, bank-sync-accounts-link
- Add linkAccountPlugin action for Redux state management
- Maintain full backward compatibility with existing GoCardless, SimpleFIN, Pluggy.ai providers
- Type-safe integration with proper TypeScript definitions
- Placeholder implementations ready for real plugin functionality

This enables the plugin architecture for bank sync while preserving existing functionality, ready for feature flag control.
2025-10-08 11:12:01 -03:00

4.3 KiB

@actual-app/plugins-core-sync-server

Core plugin utilities for Actual sync-server plugin authors.

Overview

This package provides the middleware and utilities needed to create plugins for the Actual sync-server. Plugin authors can use this to build Express-based plugins that communicate with the sync-server via IPC (Inter-Process Communication).

Installation

npm install @actual-app/plugins-core-sync-server express

Usage

Basic Plugin Setup

Create a plugin that responds to HTTP requests through the sync-server:

import express from 'express';
import { attachPluginMiddleware } from '@actual-app/plugins-core-sync-server';

const app = express();

// Use JSON middleware for parsing request bodies
app.use(express.json());

// Attach the plugin middleware to enable IPC communication
attachPluginMiddleware(app);

// Define your routes as you normally would
app.get('/hello', (req, res) => {
  res.json({ message: 'Hello from plugin!' });
});

app.post('/data', (req, res) => {
  const { name } = req.body;
  res.json({ received: name });
});

// Note: You don't need to call app.listen()
// The plugin runs as a forked process and communicates via IPC
console.log('Plugin is ready');

Plugin Manifest

Each plugin must have a manifest.ts file for type safety:

import { PluginManifest } from '@actual-app/plugins-core-sync-server';

export const manifest: PluginManifest = {
  name: 'my-plugin',
  version: '1.0.0',
  description: 'My awesome plugin',
  entry: 'dist/index.js',
  author: 'Your Name',
  license: 'MIT',
  routes: [
    {
      path: '/hello',
      methods: ['GET'],
      auth: 'anonymous',
      description: 'Public hello world endpoint',
    },
  ],
};

This is automatically converted to manifest.json during the build process.

Project Structure

my-plugin/
├── src/
│   ├── index.ts          # Main plugin code
│   └── manifest.ts       # TypeScript manifest (with type safety)
├── dist/
│   ├── index.js          # Compiled JavaScript
│   └── manifest.js       # Compiled manifest (for build process)
├── manifest.json         # JSON manifest (generated)
├── package.json
├── tsconfig.json
├── scripts/
│   ├── build-manifest.js # Converts TS manifest to JSON
│   └── build-zip.js      # Creates distribution zip
└── README.md

The build process creates: {packageName}.{version}.zip

Accessing Plugin Routes

Once your plugin is loaded by the sync-server, it will be accessible via:

http://your-server/plugins-api/<plugin-slug>/<your-route>

For example, if your plugin slug is my-plugin and you have a route /hello:

http://your-server/plugins-api/my-plugin/hello

API

attachPluginMiddleware(app: Express): void

Attaches the plugin middleware to your Express app. This sets up IPC communication with the sync-server.

Parameters:

  • app: Your Express application instance

Example:

import express from 'express';
import { attachPluginMiddleware } from '@actual-app/plugins-core-sync-server';

const app = express();
attachPluginMiddleware(app);

Types

The package exports TypeScript types for plugin development:

  • PluginRequest: IPC request structure from sync-server
  • PluginResponse: IPC response structure to sync-server
  • PluginError: IPC error structure
  • PluginReady: Plugin ready message structure
  • PluginManifest: Plugin manifest file structure
  • PluginRoute: Route configuration for manifest
  • AuthLevel: Authentication level type ('anonymous', 'authenticated', 'admin')
  • PluginExpressRequest: Express Request with plugin context
  • PluginExpressResponse: Express Response type
  • UserInfo: User information extracted from request

How It Works

  1. The sync-server loads plugins from the plugins directory
  2. Each plugin is forked as a child process
  3. HTTP requests to /plugins-api/<plugin-slug>/* are intercepted by the sync-server
  4. The sync-server sends the request data to the plugin via IPC
  5. The plugin's Express app processes the request
  6. The plugin sends the response back to sync-server via IPC
  7. The sync-server returns the response to the original HTTP client

This architecture allows plugin authors to write standard Express code without worrying about IPC details.

License

MIT