import { MastraBase } from './chunk-WENZPAHS.js';
import { execFile } from 'child_process';
import { realpathSync } from 'fs';
import { relative } from 'path';

// src/storage/base.ts
var EDITOR_DOMAINS = [
  "agents",
  "promptBlocks",
  "scorerDefinitions",
  "mcpClients",
  "mcpServers",
  "workspaces",
  "skills"
];
function normalizePerPage(perPageInput, defaultValue) {
  if (perPageInput === false) {
    return Number.MAX_SAFE_INTEGER;
  } else if (perPageInput === 0) {
    return 0;
  } else if (typeof perPageInput === "number" && perPageInput > 0) {
    return perPageInput;
  } else if (typeof perPageInput === "number" && perPageInput < 0) {
    throw new Error("perPage must be >= 0");
  }
  return defaultValue;
}
function calculatePagination(page, perPageInput, normalizedPerPage) {
  return {
    offset: perPageInput === false ? 0 : page * normalizedPerPage,
    perPage: perPageInput === false ? false : normalizedPerPage
  };
}
var MastraCompositeStore = class extends MastraBase {
  hasInitialized = null;
  shouldCacheInit = true;
  id;
  stores;
  /**
   * When true, automatic initialization (table creation/migrations) is disabled.
   */
  disableInit = false;
  constructor(config) {
    const name = config.name ?? "MastraCompositeStore";
    if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
      throw new Error(`${name}: id must be provided and cannot be empty.`);
    }
    super({
      component: "STORAGE",
      name
    });
    this.id = config.id;
    this.disableInit = config.disableInit ?? false;
    if (config.default || config.editor || config.domains) {
      const defaultStores = config.default?.stores;
      const editorStores = config.editor?.stores;
      const domainOverrides = config.domains ?? {};
      const hasDefaultDomains = defaultStores && Object.values(defaultStores).some((v) => v !== void 0);
      const hasEditorDomains = editorStores && Object.values(editorStores).some((v) => v !== void 0);
      const hasOverrideDomains = Object.values(domainOverrides).some((v) => v !== void 0);
      if (!hasDefaultDomains && !hasEditorDomains && !hasOverrideDomains) {
        throw new Error(
          "MastraCompositeStore requires at least one storage source. Provide a default storage, an editor storage, or domain overrides."
        );
      }
      const editorDomainSet = new Set(EDITOR_DOMAINS);
      const resolve = (key) => {
        if (domainOverrides[key] !== void 0) return domainOverrides[key];
        if (editorDomainSet.has(key) && editorStores?.[key] !== void 0) return editorStores[key];
        return defaultStores?.[key];
      };
      this.stores = {
        memory: resolve("memory"),
        workflows: resolve("workflows"),
        scores: resolve("scores"),
        observability: resolve("observability"),
        agents: resolve("agents"),
        datasets: resolve("datasets"),
        experiments: resolve("experiments"),
        promptBlocks: resolve("promptBlocks"),
        scorerDefinitions: resolve("scorerDefinitions"),
        mcpClients: resolve("mcpClients"),
        mcpServers: resolve("mcpServers"),
        workspaces: resolve("workspaces"),
        skills: resolve("skills"),
        blobs: resolve("blobs"),
        backgroundTasks: resolve("backgroundTasks"),
        channels: resolve("channels")
      };
    }
  }
  /**
   * 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 });
   * }
   * ```
   */
  async getStore(storeName) {
    return this.stores?.[storeName];
  }
  /**
   * Initialize all domain stores.
   * This creates necessary tables, indexes, and performs any required migrations.
   */
  async init() {
    if (this.shouldCacheInit && await this.hasInitialized) {
      return;
    }
    const initTasks = [];
    if (this.stores?.memory) {
      initTasks.push(this.stores.memory.init());
    }
    if (this.stores?.workflows) {
      initTasks.push(this.stores.workflows.init());
    }
    if (this.stores?.scores) {
      initTasks.push(this.stores.scores.init());
    }
    if (this.stores?.observability) {
      initTasks.push(this.stores.observability.init());
    }
    if (this.stores?.agents) {
      initTasks.push(this.stores.agents.init());
    }
    if (this.stores?.datasets) {
      initTasks.push(this.stores.datasets.init());
    }
    if (this.stores?.experiments) {
      initTasks.push(this.stores.experiments.init());
    }
    if (this.stores?.promptBlocks) {
      initTasks.push(this.stores.promptBlocks.init());
    }
    if (this.stores?.scorerDefinitions) {
      initTasks.push(this.stores.scorerDefinitions.init());
    }
    if (this.stores?.mcpClients) {
      initTasks.push(this.stores.mcpClients.init());
    }
    if (this.stores?.mcpServers) {
      initTasks.push(this.stores.mcpServers.init());
    }
    if (this.stores?.workspaces) {
      initTasks.push(this.stores.workspaces.init());
    }
    if (this.stores?.skills) {
      initTasks.push(this.stores.skills.init());
    }
    if (this.stores?.blobs) {
      initTasks.push(this.stores.blobs.init());
    }
    if (this.stores?.backgroundTasks) {
      initTasks.push(this.stores.backgroundTasks.init());
    }
    if (this.stores?.channels) {
      initTasks.push(this.stores.channels.init());
    }
    this.hasInitialized = Promise.all(initTasks).then(() => true);
    await this.hasInitialized;
  }
};
var MastraStorage = class extends MastraCompositeStore {
};

// src/storage/domains/base.ts
var StorageDomain = class extends MastraBase {
  /**
   * Initialize the storage domain.
   * This should create any necessary tables/collections.
   * Default implementation is a no-op - override in adapters that need initialization.
   */
  async init() {
  }
};

// src/storage/domains/versioned.ts
var ENTITY_ORDER_BY_SET = {
  createdAt: true,
  updatedAt: true
};
var SORT_DIRECTION_SET = {
  ASC: true,
  DESC: true
};
var VERSION_ORDER_BY_SET = {
  versionNumber: true,
  createdAt: true
};
var VersionedStorageDomain = class extends StorageDomain {
  // ==========================================================================
  // Concrete resolution methods
  // ==========================================================================
  /**
   * Strips version metadata fields from a version row, leaving only snapshot config fields.
   */
  extractSnapshotConfig(version) {
    const result = {};
    const metadataSet = new Set(this.versionMetadataFields);
    for (const [key, value] of Object.entries(version)) {
      if (!metadataSet.has(key)) {
        result[key] = value;
      }
    }
    return result;
  }
  /**
   * Resolves an entity by merging its thin record with the active or latest version config.
   * - `{ status: 'draft' }` — resolve with the latest version.
   * - `{ status: 'published' }` (default) — resolve with the active version, falling back to latest.
   * - `{ versionId: '...' }` — resolve with a specific version by ID.
   */
  async getByIdResolved(id, options) {
    const entity = await this.getById(id);
    if (!entity) {
      return null;
    }
    return this.resolveEntity(entity, options);
  }
  /**
   * Lists entities with version resolution.
   * When `status` is `'draft'`, each entity is resolved with its latest version.
   * When `status` is `'published'` (default), each entity is resolved with its active version.
   */
  async listResolved(args) {
    const result = await this.list(args);
    const status = args?.status;
    const entities = result[this.listKey];
    const resolved = await Promise.all(
      entities.map((entity) => this.resolveEntity(entity, { status }))
    );
    return {
      ...result,
      [this.listKey]: resolved
    };
  }
  /**
   * Resolves a single entity by merging it with its active or latest version.
   * - `{ versionId: '...' }` — resolve with a specific version by ID.
   * - `{ status: 'published' }` (default) — use activeVersionId, fall back to latest.
   * - `{ status: 'draft' }` — always use the latest version.
   */
  async resolveEntity(entity, options) {
    const status = options?.status || "published";
    let version = null;
    if (options?.versionId) {
      version = await this.getVersion(options.versionId);
    } else if (status === "draft") {
      version = await this.getLatestVersion(entity.id);
    } else {
      if (entity.activeVersionId) {
        version = await this.getVersion(entity.activeVersionId);
        if (!version) {
          this.logger?.warn?.(
            `Entity ${entity.id} has activeVersionId ${entity.activeVersionId} but version not found. Falling back to latest version.`
          );
        }
      }
      if (!version) {
        version = await this.getLatestVersion(entity.id);
      }
    }
    if (version) {
      const snapshotConfig = this.extractSnapshotConfig(version);
      return {
        ...entity,
        ...snapshotConfig,
        resolvedVersionId: version.id
      };
    }
    return entity;
  }
  // ==========================================================================
  // Protected Helper Methods
  // ==========================================================================
  parseOrderBy(orderBy, defaultDirection = "DESC") {
    return {
      field: orderBy?.field && orderBy.field in ENTITY_ORDER_BY_SET ? orderBy.field : "createdAt",
      direction: orderBy?.direction && orderBy.direction in SORT_DIRECTION_SET ? orderBy.direction : defaultDirection
    };
  }
  parseVersionOrderBy(orderBy, defaultDirection = "DESC") {
    return {
      field: orderBy?.field && orderBy.field in VERSION_ORDER_BY_SET ? orderBy.field : "versionNumber",
      direction: orderBy?.direction && orderBy.direction in SORT_DIRECTION_SET ? orderBy.direction : defaultDirection
    };
  }
};
var GitHistory = class {
  /** Cache: dir → repo root (string) or `false` if not a repo. */
  repoRootCache = /* @__PURE__ */ new Map();
  /** Cache: `dir:filename:limit` → ordered commits (newest first). */
  commitCache = /* @__PURE__ */ new Map();
  /** Cache: `dir:commitHash:filename` → parsed JSON. */
  snapshotCache = /* @__PURE__ */ new Map();
  // ===========================================================================
  // Public API
  // ===========================================================================
  /**
   * Returns `true` if `dir` is inside a Git repository.
   * Result is cached after the first call per directory.
   */
  async isGitRepo(dir) {
    const cached = this.repoRootCache.get(dir);
    if (cached === false) return false;
    if (typeof cached === "string") return true;
    try {
      const root = (await this.exec(dir, ["rev-parse", "--show-toplevel"])).trim();
      this.repoRootCache.set(dir, root);
      return true;
    } catch {
      this.repoRootCache.set(dir, false);
      return false;
    }
  }
  /**
   * Get the list of commits that touched a specific file, newest first.
   * Returns an empty array if Git is unavailable or the file has no history.
   *
   * @param dir      Absolute path to the storage directory
   * @param filename The JSON filename relative to `dir` (e.g., 'agents.json')
   * @param limit    Maximum number of commits to retrieve
   */
  async getFileHistory(dir, filename, limit = 50) {
    const cacheKey = `${dir}:${filename}:${limit}`;
    if (this.commitCache.has(cacheKey)) {
      return this.commitCache.get(cacheKey);
    }
    if (!await this.isGitRepo(dir)) {
      this.commitCache.set(cacheKey, []);
      return [];
    }
    try {
      const raw = await this.exec(dir, [
        "log",
        `--max-count=${limit}`,
        "--format=%H|%aI|%aN|%s",
        "--follow",
        "--",
        filename
      ]);
      const commits = [];
      for (const line of raw.split("\n")) {
        const trimmed = line.trim();
        if (!trimmed) continue;
        const pipeIdx1 = trimmed.indexOf("|");
        const pipeIdx2 = trimmed.indexOf("|", pipeIdx1 + 1);
        const pipeIdx3 = trimmed.indexOf("|", pipeIdx2 + 1);
        if (pipeIdx1 === -1 || pipeIdx2 === -1 || pipeIdx3 === -1) continue;
        commits.push({
          hash: trimmed.slice(0, pipeIdx1),
          date: new Date(trimmed.slice(pipeIdx1 + 1, pipeIdx2)),
          author: trimmed.slice(pipeIdx2 + 1, pipeIdx3),
          message: trimmed.slice(pipeIdx3 + 1)
        });
      }
      this.commitCache.set(cacheKey, commits);
      return commits;
    } catch {
      this.commitCache.set(cacheKey, []);
      return [];
    }
  }
  /**
   * Read and parse a JSON file at a specific Git commit.
   * Returns the parsed entity map, or `null` if the file didn't exist at that commit.
   *
   * @param dir        Absolute path to the storage directory
   * @param commitHash Full or abbreviated commit SHA
   * @param filename   The JSON filename relative to `dir` (e.g., 'agents.json')
   */
  async getFileAtCommit(dir, commitHash, filename) {
    const cacheKey = `${dir}:${commitHash}:${filename}`;
    if (this.snapshotCache.has(cacheKey)) {
      return this.snapshotCache.get(cacheKey);
    }
    if (!await this.isGitRepo(dir)) return null;
    try {
      const relPath = this.relativeToRepo(dir, filename);
      const raw = await this.exec(dir, ["show", `${commitHash}:${relPath}`]);
      const parsed = JSON.parse(raw);
      this.snapshotCache.set(cacheKey, parsed);
      return parsed;
    } catch {
      return null;
    }
  }
  /**
   * Invalidate all caches. Call after external operations that change Git state
   * (e.g., the user commits or pulls).
   */
  invalidateCache() {
    this.repoRootCache.clear();
    this.commitCache.clear();
    this.snapshotCache.clear();
  }
  // ===========================================================================
  // Internals
  // ===========================================================================
  /**
   * Get the relative path from the Git repo root to a file in the storage directory.
   */
  relativeToRepo(dir, filename) {
    const root = this.repoRootCache.get(dir);
    if (!root) {
      throw new Error(`Not a git repository: ${dir}`);
    }
    const realRoot = realpathSync(root);
    const realDir = realpathSync(dir);
    const relDir = relative(realRoot, realDir);
    return relDir ? `${relDir}/${filename}` : filename;
  }
  /**
   * Execute a git command and return stdout.
   */
  exec(cwd, args) {
    return new Promise((resolve, reject) => {
      execFile("git", args, { cwd, maxBuffer: 10 * 1024 * 1024 }, (error, stdout) => {
        if (error) reject(error);
        else resolve(stdout);
      });
    });
  }
};

// src/storage/filesystem-versioned.ts
var GIT_VERSION_PREFIX = "git-";
var FilesystemVersionedHelpers = class _FilesystemVersionedHelpers {
  db;
  entitiesFile;
  parentIdField;
  name;
  versionMetadataFields;
  gitHistoryLimit;
  /**
   * In-memory entity records (thin metadata), keyed by entity ID.
   */
  entities = /* @__PURE__ */ new Map();
  /**
   * In-memory version records, keyed by version ID.
   * Includes both in-memory/hydrated versions and git-based versions (metadata only).
   */
  versions = /* @__PURE__ */ new Map();
  /**
   * Whether we've loaded from disk yet.
   */
  hydrated = false;
  /**
   * Git history utility instance (shared across all helpers).
   */
  static gitHistory = new GitHistory();
  /**
   * Promise that resolves when git history has been loaded.
   * null means git history loading hasn't been triggered yet.
   */
  gitHistoryPromise = null;
  /**
   * The highest version number from git history, per entity ID.
   * Used to assign version numbers to new in-memory versions that continue
   * after the git history.
   */
  gitVersionCounts = /* @__PURE__ */ new Map();
  constructor(config) {
    this.db = config.db;
    this.entitiesFile = config.entitiesFile;
    this.parentIdField = config.parentIdField;
    this.name = config.name;
    this.versionMetadataFields = config.versionMetadataFields;
    this.gitHistoryLimit = config.gitHistoryLimit ?? 50;
  }
  /**
   * Check if a version ID represents a git-based version.
   */
  static isGitVersion(id) {
    return id.startsWith(GIT_VERSION_PREFIX);
  }
  /**
   * Hydrate in-memory state from the on-disk JSON file.
   * For each entry on disk, creates an in-memory entity (status: 'published')
   * and a synthetic version with the snapshot config.
   *
   * Also kicks off async git history loading in the background.
   * Version numbers for hydrated entities are assigned as 1 initially,
   * but will be reassigned after git history loads.
   */
  hydrate() {
    if (this.hydrated) return;
    this.hydrated = true;
    const diskData = this.db.readDomain(this.entitiesFile);
    for (const [entityId, snapshotConfig] of Object.entries(diskData)) {
      if (!snapshotConfig || typeof snapshotConfig !== "object") continue;
      const versionId = `hydrated-${entityId}-v1`;
      const now = /* @__PURE__ */ new Date();
      const entity = {
        id: entityId,
        status: "published",
        activeVersionId: versionId,
        createdAt: now,
        updatedAt: now
      };
      this.entities.set(entityId, entity);
      const version = {
        id: versionId,
        [this.parentIdField]: entityId,
        versionNumber: 1,
        ...snapshotConfig,
        createdAt: now
      };
      this.versions.set(versionId, version);
    }
    this.gitHistoryPromise = this.loadGitHistory();
  }
  /**
   * Ensure git history has been loaded before proceeding.
   * Call this in version-related methods to ensure git versions are available.
   */
  async ensureGitHistory() {
    this.hydrate();
    if (this.gitHistoryPromise) {
      await this.gitHistoryPromise;
    }
  }
  /**
   * Load git commit history for the domain's JSON file.
   * Creates read-only version records (metadata + snapshot config) for each
   * commit where an entity existed. Reassigns version numbers for
   * hydrated (current disk) versions to sit on top of git history.
   */
  async loadGitHistory() {
    const git = _FilesystemVersionedHelpers.gitHistory;
    const dir = this.db.dir;
    const isRepo = await git.isGitRepo(dir);
    if (!isRepo) return;
    const commits = await git.getFileHistory(dir, this.entitiesFile, this.gitHistoryLimit);
    if (commits.length === 0) return;
    const orderedCommits = [...commits].reverse();
    const entityVersionCount = /* @__PURE__ */ new Map();
    const previousSnapshots = /* @__PURE__ */ new Map();
    for (let i = 0; i < orderedCommits.length; i++) {
      const commit = orderedCommits[i];
      const fileContent = await git.getFileAtCommit(
        dir,
        commit.hash,
        this.entitiesFile
      );
      if (!fileContent) continue;
      for (const [entityId, snapshotConfig] of Object.entries(fileContent)) {
        if (!snapshotConfig || typeof snapshotConfig !== "object") continue;
        const serialized = JSON.stringify(snapshotConfig);
        if (previousSnapshots.get(entityId) === serialized) continue;
        previousSnapshots.set(entityId, serialized);
        const count = (entityVersionCount.get(entityId) ?? 0) + 1;
        entityVersionCount.set(entityId, count);
        const versionId = `${GIT_VERSION_PREFIX}${commit.hash}-${entityId}`;
        if (this.versions.has(versionId)) continue;
        const version = {
          id: versionId,
          [this.parentIdField]: entityId,
          versionNumber: count,
          changeMessage: commit.message,
          ...snapshotConfig,
          createdAt: commit.date
        };
        this.versions.set(versionId, version);
      }
    }
    this.gitVersionCounts = entityVersionCount;
    for (const [entityId, gitCount] of entityVersionCount) {
      const hydratedVersionId = `hydrated-${entityId}-v1`;
      const version = this.versions.get(hydratedVersionId);
      if (version) {
        version.versionNumber = gitCount + 1;
      }
    }
  }
  // ==========================================================================
  // Disk persistence — only published snapshot configs
  // ==========================================================================
  /**
   * Write the published snapshot config for an entity to disk.
   * Strips all entity metadata and version metadata fields, leaving only
   * the clean primitive configuration.
   */
  persistToDisk() {
    const diskData = {};
    for (const [entityId, entity] of this.entities) {
      if (entity.status !== "published" || !entity.activeVersionId) continue;
      const version = this.versions.get(entity.activeVersionId);
      if (!version) continue;
      const snapshotConfig = this.extractSnapshotConfig(version);
      diskData[entityId] = snapshotConfig;
    }
    this.db.writeDomain(this.entitiesFile, diskData);
  }
  /**
   * Extract the snapshot config from a version, stripping version metadata fields.
   */
  extractSnapshotConfig(version) {
    const metadataSet = new Set(this.versionMetadataFields);
    const result = {};
    for (const [key, value] of Object.entries(version)) {
      if (!metadataSet.has(key)) {
        result[key] = value;
      }
    }
    return result;
  }
  // ==========================================================================
  // Entity CRUD
  // ==========================================================================
  async getById(id) {
    this.hydrate();
    return this.entities.has(id) ? structuredClone(this.entities.get(id)) : null;
  }
  async createEntity(id, entity) {
    this.hydrate();
    if (this.entities.has(id)) {
      throw new Error(`${this.name}: entity with id ${id} already exists`);
    }
    this.entities.set(id, structuredClone(entity));
    return structuredClone(entity);
  }
  async updateEntity(id, updates) {
    this.hydrate();
    const existing = this.entities.get(id);
    if (!existing) {
      throw new Error(`${this.name}: entity with id ${id} not found`);
    }
    const updated = { ...existing };
    for (const [key, value] of Object.entries(updates)) {
      if (key === "id") continue;
      if (value === void 0) continue;
      if (key === "metadata" && typeof value === "object" && value !== null) {
        updated["metadata"] = {
          ...updated["metadata"] ?? {},
          ...value
        };
      } else {
        updated[key] = value;
      }
    }
    updated["updatedAt"] = /* @__PURE__ */ new Date();
    const updatedEntity = updated;
    this.entities.set(id, structuredClone(updatedEntity));
    const wasPublished = existing.status === "published";
    const isPublished = updatedEntity.status === "published" && updatedEntity.activeVersionId;
    if (isPublished || wasPublished && updates["status"] !== void 0) {
      this.persistToDisk();
    }
    return structuredClone(updatedEntity);
  }
  async deleteEntity(id) {
    this.hydrate();
    this.entities.delete(id);
    await this.deleteVersionsByParentId(id);
    this.persistToDisk();
  }
  async listEntities(args) {
    this.hydrate();
    const { page = 0, perPage: perPageInput, orderBy, filters, listKey } = args;
    const perPage = normalizePerPage(perPageInput, 100);
    if (page < 0) throw new Error("page must be >= 0");
    let entities = Array.from(this.entities.values());
    if (filters) {
      for (const [key, value] of Object.entries(filters)) {
        if (value === void 0) continue;
        if (key === "metadata" && typeof value === "object" && value !== null) {
          entities = entities.filter((e) => {
            const meta = e["metadata"];
            if (!meta) return false;
            return Object.entries(value).every(
              ([k, v]) => JSON.stringify(meta[k]) === JSON.stringify(v)
            );
          });
        } else {
          entities = entities.filter((e) => e[key] === value);
        }
      }
    }
    const field = orderBy?.field ?? "createdAt";
    const direction = orderBy?.direction ?? "DESC";
    entities.sort((a, b) => {
      const aVal = new Date(a[field]).getTime();
      const bVal = new Date(b[field]).getTime();
      return direction === "ASC" ? aVal - bVal : bVal - aVal;
    });
    const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
    return {
      [listKey]: entities.slice(offset, offset + perPage),
      total: entities.length,
      page,
      perPage: perPageForResponse,
      hasMore: offset + perPage < entities.length
    };
  }
  // ==========================================================================
  // Version Methods (in-memory + git history)
  // ==========================================================================
  async createVersion(input) {
    await this.ensureGitHistory();
    if (this.versions.has(input.id)) {
      throw new Error(`${this.name}: version with id ${input.id} already exists`);
    }
    const parentId = input[this.parentIdField];
    for (const v of this.versions.values()) {
      if (v[this.parentIdField] === parentId && v.versionNumber === input.versionNumber) {
        throw new Error(`${this.name}: version number ${input.versionNumber} already exists for entity ${parentId}`);
      }
    }
    const version = {
      ...input,
      createdAt: /* @__PURE__ */ new Date()
    };
    this.versions.set(input.id, structuredClone(version));
    return structuredClone(version);
  }
  async getVersion(id) {
    await this.ensureGitHistory();
    return this.versions.has(id) ? structuredClone(this.versions.get(id)) : null;
  }
  async getVersionByNumber(entityId, versionNumber) {
    await this.ensureGitHistory();
    for (const v of this.versions.values()) {
      if (v[this.parentIdField] === entityId && v.versionNumber === versionNumber) {
        return structuredClone(v);
      }
    }
    return null;
  }
  async getLatestVersion(entityId) {
    await this.ensureGitHistory();
    let latest = null;
    for (const v of this.versions.values()) {
      if (v[this.parentIdField] === entityId) {
        if (!latest || v.versionNumber > latest.versionNumber) {
          latest = v;
        }
      }
    }
    return latest ? structuredClone(latest) : null;
  }
  async listVersions(input, parentIdField) {
    await this.ensureGitHistory();
    const { page = 0, perPage: perPageInput, orderBy } = input;
    const entityId = input[parentIdField];
    const perPage = normalizePerPage(perPageInput, 20);
    if (page < 0) throw new Error("page must be >= 0");
    let versions = Array.from(this.versions.values()).filter(
      (v) => v[this.parentIdField] === entityId
    );
    const field = orderBy?.field ?? "versionNumber";
    const direction = orderBy?.direction ?? "DESC";
    versions.sort((a, b) => {
      const aVal = field === "createdAt" ? new Date(a.createdAt).getTime() : a.versionNumber;
      const bVal = field === "createdAt" ? new Date(b.createdAt).getTime() : b.versionNumber;
      return direction === "ASC" ? aVal - bVal : bVal - aVal;
    });
    const { offset, perPage: perPageForResponse } = calculatePagination(page, perPageInput, perPage);
    return {
      versions: versions.slice(offset, offset + perPage),
      total: versions.length,
      page,
      perPage: perPageForResponse,
      hasMore: offset + perPage < versions.length
    };
  }
  async deleteVersion(id) {
    await this.ensureGitHistory();
    if (_FilesystemVersionedHelpers.isGitVersion(id)) return;
    this.versions.delete(id);
  }
  async deleteVersionsByParentId(entityId) {
    await this.ensureGitHistory();
    for (const [versionId, version] of this.versions) {
      if (version[this.parentIdField] === entityId) {
        if (_FilesystemVersionedHelpers.isGitVersion(versionId)) continue;
        this.versions.delete(versionId);
      }
    }
  }
  async countVersions(entityId) {
    await this.ensureGitHistory();
    let count = 0;
    for (const v of this.versions.values()) {
      if (v[this.parentIdField] === entityId) {
        count++;
      }
    }
    return count;
  }
  async getNextVersionNumber(entityId) {
    await this.ensureGitHistory();
    return this._getNextVersionNumber(entityId);
  }
  _getNextVersionNumber(entityId) {
    const gitCount = this.gitVersionCounts.get(entityId) ?? 0;
    let maxVersion = gitCount;
    for (const v of this.versions.values()) {
      if (v[this.parentIdField] === entityId) {
        maxVersion = Math.max(maxVersion, v.versionNumber);
      }
    }
    return maxVersion + 1;
  }
  async dangerouslyClearAll() {
    this.entities.clear();
    this.versions.clear();
    this.gitVersionCounts.clear();
    this.gitHistoryPromise = null;
    this.hydrated = false;
    this.db.clearDomain(this.entitiesFile);
  }
};

export { EDITOR_DOMAINS, FilesystemVersionedHelpers, GitHistory, MastraCompositeStore, MastraStorage, StorageDomain, VersionedStorageDomain, calculatePagination, normalizePerPage };
//# sourceMappingURL=chunk-5R5VI3A5.js.map
//# sourceMappingURL=chunk-5R5VI3A5.js.map