Storage Plugins

Storage plugins provide backends for storing events, files, and relationships in Trove.

Storage Types

Event Storage

Stores event data and metadata:

interface EventStoragePlugin extends StoragePlugin {
  capabilities: ["storage:events"];

  saveEvent(event: Event): Promise<Event>;
  getEvent(id: EventId): Promise<Event | null>;
  queryEvents(query: EventQuery): Promise<Event[]>;
}

File Storage

Handles binary and text file data:

interface FileStoragePlugin extends StoragePlugin {
  capabilities: ["storage:files"];

  saveFile(file: EventFile): Promise<string>;
  getFile(fileId: string): Promise<EventFile | null>;
  getFileData(fileId: string): Promise<Uint8Array | string>;
}

Manages relationships between events:

interface LinkStoragePlugin extends StoragePlugin {
  capabilities: ["storage:links"];

  saveLink(sourceEventId: EventId, link: EventLink): Promise<void>;
  getLinks(eventId: EventId, options?: { type?: string }): Promise<EventLink[]>;
  getLinkedEvents(
    eventId: EventId,
    options?: { type?: string },
  ): Promise<Event[]>;
}

Official Storage Plugins

JSON File Storage

Simple file-based storage for development:

import { Trove } from "trove/core/mod.ts";

const trove = new Trove({
  storage: {
    events: {
      plugin: "storage-json-file",
      options: {
        directory: "./data/events",
      },
    },
  },
});

SQLite Storage

Embedded database storage:

{
  storage: {
    events: {
      plugin: "storage-sqlite",
      options: {
        path: "./data/events.db"
      }
    }
  }
}

S3 File Storage

Cloud storage for files:

{
  storage: {
    files: {
      plugin: "storage-s3",
      options: {
        region: "us-west-2",
        bucket: "my-events",
        accessKeyId: "...",
        secretAccessKey: "..."
      }
    }
  }
}

Creating Storage Plugins

Basic Structure

export default {
  name: "my-storage",
  capabilities: ["storage:events"],

  async initialize(core) {
    // Setup storage
    this.connection = await createDatabase(core.config);
  },

  async shutdown() {
    // Cleanup
    await this.connection.close();
  },

  // Implement storage interface
  async saveEvent(event) {
    // Store event
    return event;
  },

  async getEvent(id) {
    // Mock implementation to retrieve event
    const event = await this.database.getEventById(id);

    return event;
  },

  async queryEvents(query) {
    // Mock implementation to search events
    const events = await this.database.searchEvents(query);

    return events;
  },
};

Query Support

Storage plugins should support flexible queries:

interface EventQuery {
  schema?: string | string[];
  producer?: string | string[];
  timeRange?: {
    start?: string;
    end?: string;
  };
  links?: {
    type?: string;
    targetEvent?: EventId;
  }[];
  payload?: Record<string, any>;
  limit?: number;
  offset?: number;
  sort?: {
    field: string;
    direction: "asc" | "desc";
  }[];
}

Transactions

Optional transaction support:

interface TransactionalStoragePlugin extends StoragePlugin {
  beginTransaction(): Promise<void>;
  commitTransaction(): Promise<void>;
  rollbackTransaction(): Promise<void>;
}

Best Practices

  1. Implement proper error handling
  2. Use connection pooling when appropriate
  3. Support efficient querying
  4. Implement proper cleanup
  5. Consider implementing transactions
  6. Document performance characteristics
  7. Handle concurrent access
  8. Implement proper logging