Plugin Framework
Plugin Configuration

Plugin Configuration Reference

Complete Configuration Guide for Yaci-Store Plugins

Table of Contents

  1. Configuration Overview
  2. Global Plugin Settings
  3. Plugin Type Configurations
  4. Extension Points Reference
  5. Language-Specific Configuration

Configuration Overview

Plugin configuration in yaci-store is managed through YAML files, primarily application-plugins.yml. The configuration follows a hierarchical structure that allows fine-grained control over plugin behavior.

Configuration File Structure

store:
  plugins:
    # Global settings
    enabled: true
    exit-on-error: false
 
    # Plugin variable providers
    variable-providers:
      - com.example.CustomVariableProvider
 
    # Global scripts
    scripts:
      - id: utilities
        lang: python
        file: /app/plugins/scripts/utilities.py
        enable-pool: true
      - id: utxo_utilities2
        lang: python
        file: /app/plugins/scripts/utxo.py
        enable-pool: false
 
    # Plugin initializers
    init:
      mvel:
        name: "System Initialization"
        script:
          file: /app/plugins/scripts/init.mvel
          function: initialize
      python:
        name: "System Initialization"
        script:
          file: /app/plugins/scripts/init.py
          function: initialize
 
    # Filter plugins
    filters:
      extension.point:
        - name: "Filter Name"
          lang: mvel
          expression: "condition"
 
    # Pre-action plugins
    pre-actions:
      extension.point:
        - name: "Pre Action Name"
          lang: python
          script:
            file: /path/to/script.py
            function: function_name
 
    # Post-action plugins
    post-actions:
      extension.point:
        - name: "Post Action Name"
          lang: js
          inline-script: |
            // JavaScript code
 
    # Event handler plugins
    event-handlers:
      EventType:
        - name: "Event Handler Name"
          lang: mvel
          script:
            file: /path/to/handler.mvel
            function: handleEvent

Global Plugin Settings

Basic Settings

store:
  plugins:
    enabled: true                    # Enable/disable plugin system
    exit-on-error: false            # Continue on plugin errors

enabled

  • Type: boolean
  • Default: false
  • Description: Master switch for the plugin system

exit-on-error

  • Type: boolean
  • Default: true
  • Description: Whether to stop processing on plugin errors
  • Values:
    • true: Stop processing and exit application on plugin errors
    • false: Log errors and continue processing

metrics-enabled

  • Type: boolean
  • Default: true
  • Description: Enable or disable plugin execution metrics collection
  • Details:
    • Tracks execution metrics for all plugin types (filters, pre-actions, post-actions, event handlers, schedulers)
    • Collects dual-layer metrics: in-memory counters for fast API queries + Micrometer registry for Prometheus/Grafana integration
    • Metrics include: execution counts, success/failure rates, duration statistics, and items processed
    • Required for the plugin monitoring API to return meaningful execution data
    • Disable to reduce overhead in production if monitoring is not needed
  • Values:
    • true: Enable metrics collection (recommended for monitoring and observability)
    • false: Disable metrics collection (minimal overhead, no monitoring data)

api-enabled

  • Type: boolean
  • Default: true
  • Description: Enable or disable plugin management REST API endpoints
  • Details:
    • Exposes read-only REST API at {apiPrefix}/admin/plugins/* for plugin monitoring
    • Provides endpoints to view plugin status, execution statistics, and metrics for all plugin types
    • Does not provide control operations (start/stop) - monitoring and inspection only
    • API requires metrics-enabled: true to return execution metrics and statistics
  • Values:
    • true: Enable plugin API endpoints (recommended for monitoring)
    • false: Disable plugin API endpoints (for security or if not needed)
  • Available API Endpoints (when enabled):
    • GET {apiPrefix}/admin/plugins - Overview of all plugin types and their status
    • GET {apiPrefix}/admin/plugins/filters - List all filter plugins with metrics
    • GET {apiPrefix}/admin/plugins/pre-actions - List all pre-action plugins with metrics
    • GET {apiPrefix}/admin/plugins/post-actions - List all post-action plugins with metrics
    • GET {apiPrefix}/admin/plugins/event-handlers - List all event handler plugins with metrics
    • GET {apiPrefix}/admin/plugins/schedulers - List all scheduler plugins with metrics

Variable Providers

Through variable providers, any custom variables can be exposed to plugin contexts. This is a powerful feature that can be used to inject additional functionality or data into plugin execution contexts.

store:
  plugins:
    variable-providers:
      - com.example.DatabaseVariableProvider
      - com.example.ConfigVariableProvider
      - com.example.HttpClientVariableProvider

Custom variable providers inject additional functionality into plugin contexts:

public class DatabaseVariableProvider implements VariableProvider {
 
    @Override
    public Object getValue() {
        return Map.of(
                        "custom_db", new CustomDBService(),
                        "telegram_client", new TelegramClient()
                );
    }
}

Custom variable providers can be bundled in a JAR file and placed in the plugins/ext-jars directory. They can then be referenced in the configuration.

Global Scripts

store:
  plugins:
    scripts:
      - id: utilities
        lang: python
        file: /app/plugins/scripts/utilities.py
        enable-pool: true
      - id: utxo_utilities2
        lang: python
        file: /app/plugins/scripts/utxo.py
        enable-pool: false
    filters:
      utxo.unspent.save:
        - name: Filter UTXO
          lang: python
          script:
            id: utxo_utilities2
            function: highvalue_utxos

Global scripts are defined once and can be referenced through ID in plugin configurations. They can be used across multiple plugins.

Note: enable-pool is only applicable for Python and JavaScript scripts to allow parallel execution.


Plugin Type Configurations

Filter Plugins

Filter plugins control which data gets stored in the database.

store:
  plugins:
    filters:
      # Extension point format: {store}.{target}.{action}
      utxo.unspent.save:
        - name: "High Value UTXO Filter"
          lang: mvel
          expression: "lovelaceAmount > 1000000000"
          exit-on-error: false
 
        - name: "Policy ID Filter"
          lang: spel
          expression: "amounts.?[policyId == 'abc123'].size() > 0"
 
        - name: "Complex Filter"
          lang: python
          script:
            file: /app/plugins/scripts/filters/complex_filter.py
            function: filter_utxos

Filter Configuration Options

  • name: Human-readable plugin name
  • lang: Plugin language (mvel, spel, js, python)
  • expression: Simple boolean expression (MVEL/SpEL only)
  • inline-script: Script code embedded in configuration
  • script: External script file reference
  • exit-on-error: Plugin-specific error handling override

Pre-Action Plugins

Pre-action plugins modify data before it's stored.

store:
  plugins:
    pre-actions:
      metadata.save:
        - name: "Metadata Enrichment"
          lang: python
          script:
            file: /app/plugins/scripts/actions/enrich_metadata.py
            function: enrich
 
        - name: "Field Normalization"
          lang: mvel
          inline-script: |
            modified_list = [];
            for (item : items) {
              if (item.label != null) {
                ...
              }
              modified_list.add(item);
            }
            return modified_list;

Post-Action Plugins

Post-action plugins execute after data is successfully stored.

store:
  plugins:
    post-actions:
      transaction.save:
        - name: "Webhook Notification"
          lang: js
          inline-script: |
            if (items.length > 0) {
              const payload = {
                count: items.length,
                timestamp: new Date().toISOString()
              };
              http.postJson(webhookUrl, payload);
            }
 
        - name: "Cache Update"
          lang: python
          script:
            file: /app/plugins/scripts/actions/update_cache.py
            function: update_transaction_cache

Event Handler Plugins

Event handler plugins react to blockchain events.

store:
  plugins:
    event-handlers:
      BlockEvent:
        - name: "Block Statistics"
          lang: mvel
          script:
            file: /app/plugins/scripts/handlers/block_stats.mvel
            function: processBlock
 
      TransactionEvent:
        - name: "Transaction Monitor"
          lang: python
          script:
            file: /app/plugins/scripts/handlers/tx_monitor.py
            function: handle_transaction_event
 
      AddressUtxoEvent:
        - name: "Address Tracker"
          lang: js
          inline-script: |
            console.log(`Address UTXO event: ${event.tx_input_outputs.length} changes`);
            // Process address changes

Initializer Plugins

Initializer plugins run once during application startup.

store:
  plugins:
    initializers:
      python:
        name: "Database Setup"
        script:
          file: /app/plugins/scripts/init/db_setup.py
          function: initialize_database
        exit-on-error: true
 
      mvel:
        name: "Configuration Validation"
        inline-script: |
          System.out.println("Validating plugin configuration...");
          // Validation logic

Scheduler Plugins

Scheduler plugins execute at scheduled intervals or based on cron expressions, independent of blockchain events. They are useful for periodic tasks such as cleanup operations, metrics aggregation, external API polling, and scheduled notifications.

Configuration Examples

Example 1: Interval-based Scheduler

Execute a task every N seconds using the INTERVAL schedule type:

store:
  plugins:
    enabled: true
    schedulers:
      - name: "interval-test-scheduler"
        lang: "js"
        inline-script: |
          var count = state.get('count') || 0;
          count++;
          state.put('count', count);
          console.log('>>> Interval scheduler executed: ' + count);
        schedule:
          type: INTERVAL
          value: "10"  # seconds
        exit-on-error: false

Example 2: CRON-based Scheduler

Execute a task based on cron expressions:

      - name: "cron-hourly-task"
        lang: "js"
        inline-script: |
          console.log('Hourly task executed at: ' + new Date());
          state.put('lastRun', executionTime);
          state.put('hourlyExecutions', (state.get('hourlyExecutions') || 0) + 1);
        schedule:
          type: CRON
          value: "0 0 * * * ?"  # Every hour at minute 0
        exit-on-error: false

Example 3: Metrics Aggregation (MVEL)

Using MVEL for metrics aggregation every 5 minutes:

      - name: "metrics-aggregator"
        lang: "mvel"
        inline-script: |
          // Aggregate plugin metrics
          totalExecutions = state.get('totalExecutions');
          if (totalExecutions == null) totalExecutions = 0;
          totalExecutions = totalExecutions + 1;
          state.put('totalExecutions', totalExecutions);
          state.put('lastAggregationTime', executionTime);
        schedule:
          type: CRON
          value: "0 */5 * * * ?"  # Every 5 minutes
        exit-on-error: false

Configuration Options

OptionTypeRequiredDescription
nameStringYesHuman-readable scheduler name
langStringYesScript language: js (JavaScript) or mvel or python
inline-scriptStringYes*Inline script code to execute
scriptStringYes*Path to external script file (alternative to inline-script)
scheduleObjectYesSchedule configuration (see below)
schedule.typeStringYesSchedule type: INTERVAL or CRON
schedule.valueStringYesInterval in seconds (for INTERVAL) or cron expression (for CRON)
exit-on-errorBooleanNoWhether to stop scheduler on errors (default: false)

*Either inline-script or script must be provided.

Available Context Variables

Scheduler plugins have access to the following context variables:

  • state: Global state management
    • state.get(key): Retrieve a value from global state
    • state.put(key, value): Store a value in global state
  • executionTime: Timestamp of the current execution
  • console: Logging utilities
    • console.log(message): Log informational messages
  • named_jdbc: Database access for querying blockchain data
    • named_jdbc.queryForMap(sql, params): Query single row
    • named_jdbc.queryForList(sql, params): Query multiple rows
  • All standard context variables: http, config, etc. (see Context Variables)

Schedule Types

INTERVAL

Execute at fixed time intervals specified in seconds.

Configuration:

schedule:
  type: INTERVAL
  value: "10"  # Execute every 10 seconds

Common Examples:

  • "10" - Every 10 seconds
  • "60" - Every minute
  • "300" - Every 5 minutes
  • "3600" - Every hour

CRON

Execute based on cron expressions using the standard cron syntax with an additional seconds field.

Format: seconds minutes hours day-of-month month day-of-week

Configuration:

schedule:
  type: CRON
  value: "0 0 * * * ?"  # Cron expression

Common Examples:

ExpressionDescription
"0 0 * * * ?"Every hour at minute 0
"0 */5 * * * ?"Every 5 minutes
"0 0 0 * * ?"Every day at midnight
"0 0 12 * * ?"Every day at noon
"0 0 0 * * MON"Every Monday at midnight
"0 30 9 1 * ?"First day of every month at 9:30 AM
"0 0 0 1 1 ?"January 1st at midnight

Cron Special Characters:

  • * - All values
  • ? - No specific value (for day-of-month and day-of-week)
  • - - Range (e.g., 1-5)
  • , - List of values (e.g., 1,3,5)
  • / - Increments (e.g., */5 for every 5 units)

Use Cases

Periodic Cleanup Tasks:

- name: "cleanup-old-data"
  lang: "js"
  inline-script: |
    console.log('Running cleanup task...');
    // Delete records older than 30 days
    var cutoffDate = Date.now() - (30 * 24 * 60 * 60 * 1000);
    var params = { cutoffTimestamp: cutoffDate };
    var result = named_jdbc.update(
      "DELETE FROM plugin_tracking WHERE timestamp < :cutoffTimestamp",
      params
    );
    console.log('Deleted ' + result + ' old records');
  schedule:
    type: CRON
    value: "0 0 2 * * ?"  # Daily at 2 AM

Send Data to External System:

- name: "push-metrics-to-monitoring"
  lang: "js"
  inline-script: |
    // Query blockchain metrics from database
    var blockResult = named_jdbc.queryForMap("SELECT COUNT(*) as count FROM block", {});
    var txResult = named_jdbc.queryForMap("SELECT COUNT(*) as count FROM transaction", {});
 
    // Send metrics to external monitoring system
    var payload = {
      blocks: blockResult.count,
      transactions: txResult.count
    };
    var response = http.post('https://monitoring.example.com/metrics', payload);
 
    console.log('Metrics pushed successfully: ' + response.status);
  schedule:
    type: INTERVAL
    value: "300"  # Every 5 minutes

Metrics Collection:

- name: "collect-metrics"
  lang: "mvel"
  inline-script: |
    result = named_jdbc.queryForMap("SELECT COUNT(*) as count FROM transaction", [:]);
    state.put('transactionCount', result['count']);
    state.put('lastCollected', executionTime);
  schedule:
    type: CRON
    value: "0 */10 * * * ?"  # Every 10 minutes

Extension Points Reference

Storage Extension Points

Storage extension points follow the pattern: {store}.{target}.{action}

UTXO Store

# UTXO-related extension points
utxo.unspent.save          # New unspent UTXOs
utxo.spent.save            # Newly spent UTXOs

Transaction Store

# Transaction-related extension points
transaction.save           # Transaction data
transaction.witness.save   # Transaction witnesses
transaction.withdrawal.save # Stake withdrawals

Metadata Store

# Metadata extension points
metadata.save              # Transaction metadata

Asset Store

# Asset-related extension points
asset.save                 # Asset mint/burn operations

Block Store

# Block extension points
block.save                 # Block data

Script Store

# Script-related extension points
script.save                # Script definitions
script.datum.save          # Datum storage
script.tx_script.save      # Transaction script executions

Staking Store

# Staking extension points
staking.key_registration.save    # Stake key registrations
staking.key_delegation.save      # Stake delegations
staking.pool_registration.save   # Pool registrations
staking.pool_retirement.save     # Pool retirements
staking.pool.save               # Pool status updates

Governance Store (Conway Era)

# Governance extension points
governance.gov_action_proposal.save   # Governance proposals
governance.voting_procedure.save      # Voting procedures
governance.drep_registration.save     # DRep registrations
governance.drep.save                  # DRep status updates
governance.delegation_vote.save       # Vote delegations
governance.committee_registration.save # Committee registrations
governance.committee_member.save      # Committee member updates
governance.committee_deregistration.save # Committee deregistrations

Event Types

Event handler plugins can listen to these event types:

System Events

event-handlers:
  RollbackEvent:            # Blockchain rollback
  EpochChangeEvent:         # Epoch transitions
  CommitEvent:              # Block commit events

Blockchain Data Events

event-handlers:
  BlockEvent:               # New blocks
  TransactionEvent:         # Transaction data
  MintBurnEvent:            # Asset mint/burn operations
  AuxDataEvent:             # Auxiliary data (metadata)
  ScriptEvent:              # Smart contract data
  CertificateEvent:         # Certificates
  GovernanceEvent:          # Governance actions

Store-Specific Events

event-handlers:
  TxnEvent:                 # Processed transactions
  AddressUtxoEvent:         # Address UTXO changes
  TxMetadataEvent:          # Processed metadata
  DatumEvent:               # Datum data
  TxScriptEvent:            # Script execution data
  PoolRegistrationEvent:    # Pool registrations
  StakeRegDeregEvent:       # Stake registration/deregistration

Language-Specific Configuration

MVEL Configuration

store:
  plugins:
    filters:
      utxo.unspent.save:
        - name: "MVEL Expression Filter"
          lang: mvel
          expression: |
            lovelaceAmount > 1000000 &&
            amounts.any { it.policy == "target_policy" }
 
        - name: "MVEL Script Filter"
          lang: mvel
          script:
            file: /app/plugins/scripts/complex_filter.mvel
            function: filterFunction
 
        - name: "MVEL Inline Script"
          lang: mvel
          inline-script: |
            filtered = [];
            for (item : items) {
              if (item.lovelaceAmount > threshold) {
                filtered.add(item);
              }
            }
            return filtered;

MVEL Features

  • Direct Java object access
  • Lambda expressions
  • Collection operations
  • Regex support
  • Mathematical operations

SpEL Configuration

store:
  plugins:
    filters:
      metadata.save:
        - name: "SpEL Expression Filter"
          lang: spel
          expression: "label == '721' or label == '1967'"
 
        - name: "SpEL Collection Filter"
          lang: spel
          expression: "body.contains('image') and body.length() > 100"

SpEL Limitations

  • Expression-only (no script files)
  • Limited to filter plugins
  • Spring ecosystem integration

JavaScript Configuration

store:
  plugins:
    event-handlers:
      TransactionEvent:
        - name: "JavaScript Handler"
          lang: js
          script:
            file: /app/plugins/scripts/tx_handler.js
            function: handleTransaction
 
        - name: "JavaScript Inline"
          lang: js
          inline-script: |
            function processTransactions(event, context) {
              const transactions = event.transactions;
              console.log(`Processing ${transactions.length} transactions`);
 
              for (const tx of transactions) {
                analyzeTransaction(tx, context);
              }
            }
 
            processTransactions(event, context);

JavaScript Features

  • ES6+ syntax via GraalVM Polyglot support
  • JSON processing

Python Configuration

store:
  plugins:
    pre-actions:
      utxo.unspent.save:
        - name: "Python Data Enrichment"
          lang: python
          script:
            file: /app/plugins/scripts/enrich_utxos.py
            function: enrich_with_external_data
 
        - name: "Python Inline"
          lang: python
          inline-script: |
            import json
 
            def process_items(items, context):
                logger = context.logger
                enriched = []
 
                for item in items:
                    # Enrich item data
                    item.processed_at = time.time()
                    enriched.append(item)
 
                logger.info(f"Processed {len(enriched)} items")
                return enriched
 
            # Process the items
            result = process_items(items, context)

Python Features

  • Python 3.x syntax via GraalVM Polyglot support
  • Rich data structures