@mastra/core
Version:
320 lines • 13 kB
TypeScript
import { MastraBase } from '../base.js';
import type { AgentsStorage, PromptBlocksStorage, ScorerDefinitionsStorage, MCPClientsStorage, MCPServersStorage, WorkspacesStorage, SkillsStorage, FavoritesStorage, ScoresStorage, WorkflowsStorage, MemoryStorage, ObservabilityStorage, BlobStore, DatasetsStorage, ExperimentsStorage, BackgroundTasksStorage, SchedulesStorage, ChannelsStorage, HarnessStorage, ToolProviderConnectionsStorage, NotificationsStorage, ThreadStateStorage } from './domains/index.js';
import type { PruneOptions, PruneResult, RetentionConfig } from './retention.js';
/** Map of all storage domain interfaces available in a composite store. */
export type StorageDomains = {
workflows?: WorkflowsStorage;
scores?: ScoresStorage;
memory?: MemoryStorage;
channels?: ChannelsStorage;
notifications?: NotificationsStorage;
observability?: ObservabilityStorage;
agents?: AgentsStorage;
datasets?: DatasetsStorage;
experiments?: ExperimentsStorage;
promptBlocks?: PromptBlocksStorage;
scorerDefinitions?: ScorerDefinitionsStorage;
mcpClients?: MCPClientsStorage;
mcpServers?: MCPServersStorage;
workspaces?: WorkspacesStorage;
skills?: SkillsStorage;
favorites?: FavoritesStorage;
blobs?: BlobStore;
backgroundTasks?: BackgroundTasksStorage;
schedules?: SchedulesStorage;
harness?: HarnessStorage;
toolProviderConnections?: ToolProviderConnectionsStorage;
threadState?: ThreadStateStorage;
};
/**
* Domain keys used by the Mastra Editor.
* Used by the `editor` shorthand on MastraCompositeStoreConfig to route
* all editor-related domains to a single store.
*/
export declare const EDITOR_DOMAINS: readonly ["agents", "promptBlocks", "scorerDefinitions", "mcpClients", "mcpServers", "workspaces", "skills", "favorites", "toolProviderConnections"];
/**
* Normalizes perPage input for pagination queries.
*
* @param perPageInput - The raw perPage value from the user
* @param defaultValue - The default perPage value to use when undefined (typically 40 for messages, 100 for threads)
* @returns A numeric perPage value suitable for queries (false becomes MAX_SAFE_INTEGER)
* @throws Error if perPage is a negative number
*/
export declare function normalizePerPage(perPageInput: number | false | undefined, defaultValue: number): number;
/**
* Calculates pagination offset and prepares perPage value for response.
* When perPage is false (fetch all), offset is always 0 regardless of page.
*
* @param page - The page number (0-indexed)
* @param perPageInput - The original perPage input (number, false for all, or undefined)
* @param normalizedPerPage - The normalized perPage value (from normalizePerPage)
* @returns Object with offset for query and perPage for response
*/
export declare function calculatePagination(page: number, perPageInput: number | false | undefined, normalizedPerPage: number): {
offset: number;
perPage: number | false;
};
/**
* Configuration for individual domain overrides.
* Each domain can be sourced from a different storage adapter.
*/
export type MastraStorageDomains = Partial<StorageDomains>;
/**
* Configuration options for MastraCompositeStore.
*
* Can be used in two ways:
* 1. By store implementations: `{ id, name, disableInit? }` - stores set `this.stores` directly
* 2. For composition: `{ id, default?, domains?, disableInit? }` - compose domains from multiple stores
*/
export interface MastraCompositeStoreConfig {
/**
* Unique identifier for this storage instance.
*/
id: string;
/**
* Name of the storage adapter (used for logging).
* Required for store implementations extending MastraCompositeStore.
*/
name?: string;
/**
* Default storage adapter to use for domains not explicitly specified.
* If provided, domains from this storage will be used as fallbacks.
*/
default?: MastraCompositeStore;
/**
* Storage adapter for editor-related domains (agents, promptBlocks, scorerDefinitions,
* mcpClients, mcpServers, workspaces, skills).
*
* This is a shorthand that routes all editor domains to a single store instead of
* specifying each individually in `domains`. Useful for filesystem-based storage
* where editor configs are stored as JSON files in the repository.
*
* Priority: domains > editor > default
*
* @example
* ```typescript
* new MastraCompositeStore({
* id: 'my-store',
* default: postgresStore,
* editor: filesystemStore,
* })
* ```
*/
editor?: MastraCompositeStore;
/**
* Individual domain overrides. Each domain can come from a different storage adapter.
* These take precedence over both `editor` and `default` storage.
*
* @example
* ```typescript
* domains: {
* memory: pgStore.stores?.memory,
* workflows: libsqlStore.stores?.workflows,
* }
* ```
*/
domains?: MastraStorageDomains;
/**
* When true, automatic initialization (table creation/migrations) is disabled.
* This is useful for CI/CD pipelines where you want to:
* 1. Run migrations explicitly during deployment (not at runtime)
* 2. Use different credentials for schema changes vs runtime operations
*
* When disableInit is true:
* - The storage will not automatically create/alter tables on first use
* - You must call `storage.init()` explicitly in your CI/CD scripts
*
* @example
* // In CI/CD script:
* const storage = new PostgresStore({ ...config, disableInit: false });
* await storage.init(); // Explicitly run migrations
*
* // In runtime application:
* const storage = new PostgresStore({ ...config, disableInit: true });
* // No auto-init, tables must already exist
*/
disableInit?: boolean;
/**
* Opt-in, table-granular, age-based retention policies.
*
* Declare per-domain, per-table `maxAge` policies; call `storage.prune()`
* to delete rows older than their configured age. Anything left unset is
* kept forever (no behavior change by default).
*
* @example
* ```typescript
* retention: {
* memory: {
* messages: { maxAge: '30d' },
* threads: { maxAge: '90d' },
* },
* observability: {
* spans: { maxAge: '7d' },
* },
* }
* ```
*/
retention?: RetentionConfig;
}
/**
* Base class for all Mastra storage adapters.
*
* Can be used in two ways:
*
* 1. **Extended by store implementations** (PostgresStore, LibSQLStore, etc.):
* Store implementations extend this class and set `this.stores` with their domain implementations.
*
* 2. **Directly instantiated for composition**:
* Compose domains from multiple storage backends using `default` and `domains` options.
*
* All domain-specific operations should be accessed through `getStore()`:
*
* @example
* ```typescript
* // Composition: mix domains from different stores
* const storage = new MastraCompositeStore({
* id: 'composite',
* default: pgStore,
* domains: {
* memory: libsqlStore.stores?.memory,
* },
* });
*
* // Use `editor` shorthand to route all editor domains to a filesystem store
* const storage2 = new MastraCompositeStore({
* id: 'with-fs-editor',
* default: pgStore,
* editor: filesystemStore,
* });
*
* // Access domains
* const memory = await storage.getStore('memory');
* await memory?.saveThread({ thread });
* ```
*/
/**
* Minimal interface a storage adapter sees from the Mastra instance.
* Kept narrow on purpose to avoid pulling the full Mastra type into the
* storage layer (which would create a circular import).
*/
export interface StorageMastraRef {
getAgentById?: (id: string) => {
source?: string;
__getEditorConfig?: () => unknown;
} | undefined;
listAgents?: () => Record<string, {
id: string;
source?: string;
__getEditorConfig?: () => unknown;
}> | undefined;
getEditor?: () => {
getSource?: () => 'code' | 'db' | undefined;
} | undefined;
}
export declare class MastraCompositeStore extends MastraBase {
#private;
protected hasInitialized: null | Promise<boolean>;
protected shouldCacheInit: boolean;
id: string;
stores?: StorageDomains;
protected mastra?: StorageMastraRef;
/**
* When true, automatic initialization (table creation/migrations) is disabled.
*/
disableInit: boolean;
/**
* Opt-in, table-granular, age-based retention policies. Consumed by
* `prune()`. Undefined means nothing is pruned (keep forever).
*/
protected retention?: RetentionConfig;
/**
* Retained references to the parent stores supplied via composition. `init()`
* delegates to these so the parent's own `init()` logic (pragmas, ordered
* DDL, init coalescing, etc.) runs instead of being bypassed by the
* composite iterating the inner domains in parallel — which was the cause
* of the SQLITE_BUSY / "no such table" races reported in issue #16782.
*/
protected parentDefault?: MastraCompositeStore;
protected parentEditor?: MastraCompositeStore;
constructor(config: MastraCompositeStoreConfig);
/**
* Register the Mastra instance with this storage adapter and cascade the
* reference to all owned domain stores and parent composites. Storage
* adapters that need to look up agents, editor config, etc. can read
* `this.mastra` after this is called.
* @internal
*/
__registerMastra(mastra: StorageMastraRef, seen?: Set<unknown>): void;
/**
* Get a domain-specific storage interface.
*
* @param storeName - The name of the domain to access ('memory', 'workflows', 'scores', 'observability', 'agents')
* @returns The domain storage interface, or undefined if not available
*
* @example
* ```typescript
* const memory = await storage.getStore('memory');
* if (memory) {
* await memory.saveThread({ thread });
* }
* ```
*/
getStore<K extends keyof StorageDomains>(storeName: K): Promise<StorageDomains[K] | undefined>;
/**
* Delete rows older than their configured `maxAge` across all domains that
* have a policy declared in `retention`.
*
* Prune is safe at scale: each domain deletes in bounded, batched, resumable,
* cancellable chunks (see {@link PruneOptions}). It only deletes rows. On
* SQLite/LibSQL freed pages are reused by future writes so the file stops
* growing; handing disk back to the OS is left to the underlying database and
* the operator to manage.
*
* Returns one {@link PruneResult} per table touched. A result with
* `done: false` means eligible rows remain — call `prune()` again (e.g. on
* the next cron tick) to continue.
*
* Prune is meant to run unattended (a cron tick), so a failure in one
* domain is logged and skipped rather than rejecting the whole call — the
* results already gathered for other domains are still returned, and the
* failed domain is retried naturally on the next tick.
*
* With no `retention` configured this is a no-op returning `[]`.
*/
prune(options?: PruneOptions): Promise<PruneResult[]>;
/**
* Initialize all domain stores.
*
* When a parent store was supplied via `default` or `editor`, delegate to
* its own `init()` first. Each adapter owns its `init()` contract — it may
* apply connection-level setup, run migrations, enforce DDL ordering, or
* coalesce concurrent callers. Calling each domain's `init()` directly
* against the parent's shared client would bypass all of that and can
* corrupt or partially create schema (see issue #16782 for the SQLite
* symptom).
*
* Any remaining domains that did NOT come from a parent (e.g. supplied via
* the explicit `domains` override pointing at a different store) are then
* initialized individually — but only the ones the parents didn't already
* cover, so we never double-init the same domain instance.
*/
init(): Promise<void>;
/**
* Optional lifecycle hook: release underlying client/connection handles.
* Implementations (e.g. LibSQLStore) override this to checkpoint WAL files
* and close the database client so OS handles are freed synchronously.
* Called automatically by Mastra.shutdown().
*/
close?(): Promise<void>;
}
/**
* @deprecated Use MastraCompositeStoreConfig instead. This alias will be removed in a future version.
*/
export interface MastraStorageConfig extends MastraCompositeStoreConfig {
}
/**
* @deprecated Use MastraCompositeStore instead. This alias will be removed in a future version.
*/
export declare class MastraStorage extends MastraCompositeStore {
}
//# sourceMappingURL=base.d.ts.map