import { z } from 'zod';

// src/plugins/plugin-manifest.ts
var PluginManifestSchema = z.object({
  // Basic information
  id: z.string().min(1).regex(/^[a-z0-9-]+$/),
  name: z.string().min(1),
  version: z.string().regex(/^\d+\.\d+\.\d+/),
  description: z.string().optional(),
  // Author information
  author: z.object({
    name: z.string(),
    email: z.string().email().optional(),
    url: z.string().url().optional()
  }).optional(),
  // Plugin metadata
  license: z.string().optional(),
  homepage: z.string().url().optional(),
  repository: z.string().optional(),
  // Dependencies and compatibility
  dependencies: z.record(z.string()).optional(),
  cfCmsVersion: z.string().optional(),
  // Capabilities
  capabilities: z.object({
    routes: z.boolean().optional(),
    hooks: z.boolean().optional(),
    adminPages: z.boolean().optional(),
    middleware: z.boolean().optional(),
    models: z.boolean().optional(),
    services: z.boolean().optional(),
    themes: z.boolean().optional(),
    fieldTypes: z.boolean().optional()
  }).optional(),
  // Configuration
  config: z.object({
    schema: z.record(z.any()).optional(),
    defaults: z.record(z.any()).optional()
  }).optional(),
  // Database requirements
  database: z.object({
    tables: z.array(z.string()).optional(),
    migrations: z.array(z.string()).optional()
  }).optional(),
  // Asset requirements
  assets: z.object({
    styles: z.array(z.string()).optional(),
    scripts: z.array(z.string()).optional()
  }).optional(),
  // Plugin flags
  isCore: z.boolean().optional(),
  isActive: z.boolean().optional(),
  isPublic: z.boolean().optional()
});
function validateManifest(manifest) {
  try {
    PluginManifestSchema.parse(manifest);
    return { valid: true, errors: [] };
  } catch (error) {
    if (error instanceof z.ZodError) {
      return {
        valid: false,
        errors: error.errors.map((e) => `${e.path.join(".")}: ${e.message}`)
      };
    }
    return { valid: false, errors: ["Unknown validation error"] };
  }
}
function validateDependencies(manifest, installedPlugins) {
  const errors = [];
  if (!manifest.dependencies) {
    return { valid: true, errors: [] };
  }
  for (const [depId, depVersion] of Object.entries(manifest.dependencies)) {
    const installed = installedPlugins.get(depId);
    if (!installed) {
      errors.push(`Missing dependency: ${depId}@${depVersion}`);
      continue;
    }
    if (!isVersionCompatible(installed.version, depVersion)) {
      errors.push(`Incompatible version for ${depId}: required ${depVersion}, found ${installed.version}`);
    }
  }
  return { valid: errors.length === 0, errors };
}
function isVersionCompatible(installed, required) {
  const [installedMajor] = installed.split(".");
  const [requiredMajor] = required.split(".");
  if (required.startsWith("^")) {
    return installedMajor === requiredMajor.replace("^", "");
  }
  if (required.startsWith("~")) {
    const [reqMajor, reqMinor] = required.replace("~", "").split(".");
    const [instMajor, instMinor] = installed.split(".");
    return instMajor === reqMajor && instMinor === reqMinor;
  }
  return installed === required;
}
function resolvePluginLoadOrder(plugins) {
  const errors = [];
  const order = [];
  const visited = /* @__PURE__ */ new Set();
  const visiting = /* @__PURE__ */ new Set();
  function visit(id) {
    if (visited.has(id)) return true;
    if (visiting.has(id)) {
      errors.push(`Circular dependency detected: ${id}`);
      return false;
    }
    visiting.add(id);
    const plugin = plugins.get(id);
    if (!plugin) {
      errors.push(`Plugin not found: ${id}`);
      return false;
    }
    if (plugin.dependencies) {
      for (const depId of Object.keys(plugin.dependencies)) {
        if (!visit(depId)) return false;
      }
    }
    visiting.delete(id);
    visited.add(id);
    order.push(id);
    return true;
  }
  for (const id of plugins.keys()) {
    if (!visited.has(id)) {
      visit(id);
    }
  }
  return { order, errors };
}

// src/plugins/plugin-registry.ts
var PluginRegistry = class {
  db;
  plugins = /* @__PURE__ */ new Map();
  statuses = /* @__PURE__ */ new Map();
  constructor(options) {
    this.db = options.db;
  }
  /**
   * Initialize registry - load plugins from database
   */
  async initialize() {
    try {
      const result = await this.db.prepare("SELECT * FROM plugins WHERE status != ?").bind("deleted").all();
      if (result.results) {
        for (const row of result.results) {
          const manifest = JSON.parse(row.manifest);
          const resolved = {
            ...manifest,
            path: row.path,
            entry: row.entry,
            manifestPath: row.manifest_path,
            installedAt: row.installed_at,
            updatedAt: row.updated_at,
            status: row.status,
            error: row.error
          };
          this.plugins.set(manifest.id, resolved);
          this.updateStatus(manifest.id, resolved);
        }
      }
    } catch (error) {
      console.error("[PluginRegistry] Failed to initialize:", error);
      throw error;
    }
  }
  /**
   * Register a plugin
   */
  async register(manifest, path, entry) {
    const now = Math.floor(Date.now() / 1e3);
    const resolved = {
      ...manifest,
      path,
      entry,
      manifestPath: `${path}/manifest.json`,
      installedAt: now,
      updatedAt: now,
      status: "inactive"
    };
    this.plugins.set(manifest.id, resolved);
    this.updateStatus(manifest.id, resolved);
    await this.db.prepare(`
        INSERT OR REPLACE INTO plugins 
        (id, name, version, manifest, path, entry, manifest_path, status, installed_at, updated_at)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
      `).bind(
      manifest.id,
      manifest.name,
      manifest.version,
      JSON.stringify(manifest),
      path,
      entry,
      resolved.manifestPath,
      "inactive",
      now,
      now
    ).run();
  }
  /**
   * Unregister a plugin
   */
  async unregister(id) {
    this.plugins.delete(id);
    this.statuses.delete(id);
    await this.db.prepare("UPDATE plugins SET status = ? WHERE id = ?").bind("deleted", id).run();
  }
  /**
   * Get plugin by ID
   */
  get(id) {
    return this.plugins.get(id);
  }
  /**
   * Get all registered plugins
   */
  getAll() {
    return Array.from(this.plugins.values());
  }
  /**
   * Get active plugins
   */
  getActive() {
    return Array.from(this.plugins.values()).filter((p) => p.status === "active");
  }
  /**
   * Check if plugin is registered
   */
  has(id) {
    return this.plugins.has(id);
  }
  /**
   * Activate a plugin
   */
  async activate(id) {
    const plugin = this.plugins.get(id);
    if (!plugin) throw new Error(`Plugin not found: ${id}`);
    plugin.status = "active";
    this.updateStatus(id, plugin);
    await this.db.prepare("UPDATE plugins SET status = ? WHERE id = ?").bind("active", id).run();
  }
  /**
   * Deactivate a plugin
   */
  async deactivate(id) {
    const plugin = this.plugins.get(id);
    if (!plugin) throw new Error(`Plugin not found: ${id}`);
    plugin.status = "inactive";
    this.updateStatus(id, plugin);
    await this.db.prepare("UPDATE plugins SET status = ? WHERE id = ?").bind("inactive", id).run();
  }
  /**
   * Mark plugin as errored
   */
  async markError(id, error) {
    const plugin = this.plugins.get(id);
    if (!plugin) throw new Error(`Plugin not found: ${id}`);
    plugin.status = "error";
    plugin.error = error;
    this.updateStatus(id, plugin);
    await this.db.prepare("UPDATE plugins SET status = ?, error = ? WHERE id = ?").bind("error", error, id).run();
  }
  /**
   * Get plugin status
   */
  getStatus(id) {
    return this.statuses.get(id);
  }
  /**
   * Get all plugin statuses
   */
  getAllStatuses() {
    return new Map(this.statuses);
  }
  /**
   * Resolve plugin load order based on dependencies
   */
  resolveLoadOrder() {
    const pluginMap = new Map(
      this.plugins.entries().map(([id, manifest]) => [id, manifest])
    );
    return resolvePluginLoadOrder(pluginMap);
  }
  /**
   * Update plugin status
   */
  updateStatus(id, plugin) {
    const status = {
      id: plugin.id,
      name: plugin.name,
      version: plugin.version,
      active: plugin.status === "active",
      installed: true,
      hasErrors: plugin.status === "error",
      error: plugin.error
    };
    this.statuses.set(id, status);
  }
};

// src/plugins/plugin-validator.ts
var PluginValidator = class {
  /**
   * Validate plugin manifest
   */
  validateManifest(manifest) {
    const result = validateManifest(manifest);
    return {
      valid: result.valid,
      errors: result.errors,
      warnings: []
    };
  }
  /**
   * Validate plugin dependencies
   */
  validateDependencies(manifest, registry) {
    const installedPlugins = new Map(
      registry.getAll().map((p) => [p.id, p])
    );
    const result = validateDependencies(manifest, installedPlugins);
    return {
      valid: result.valid,
      errors: result.errors,
      warnings: []
    };
  }
  /**
   * Validate plugin compatibility with cf-cms.js version
   */
  validateCompatibility(manifest, cfCmsVersion) {
    const errors = [];
    const warnings = [];
    if (!manifest.cfCmsVersion) {
      warnings.push("Plugin does not specify cfCmsVersion compatibility");
      return { valid: true, errors, warnings };
    }
    const [pluginMajor] = manifest.cfCmsVersion.split(".");
    const [cmsMajor] = cfCmsVersion.split(".");
    if (pluginMajor !== cmsMajor) {
      errors.push(
        `Plugin requires cf-cms.js ${manifest.cfCmsVersion}, but ${cfCmsVersion} is installed`
      );
    }
    return { valid: errors.length === 0, errors, warnings };
  }
  /**
   * Validate plugin security
   */
  validateSecurity(manifest) {
    const errors = [];
    const warnings = [];
    if (manifest.id.includes("..") || manifest.id.includes("/")) {
      errors.push("Plugin ID contains invalid characters");
    }
    if (!manifest.author) {
      warnings.push("Plugin does not specify author information");
    }
    if (!manifest.license) {
      warnings.push("Plugin does not specify a license");
    }
    if (!manifest.name || manifest.name.length === 0) {
      errors.push("Plugin name is required");
    }
    if (!manifest.version || !isValidSemver(manifest.version)) {
      errors.push("Plugin version must be valid semantic version (e.g., 1.0.0)");
    }
    return { valid: errors.length === 0, errors, warnings };
  }
  /**
   * Validate complete plugin before installation
   */
  validateForInstallation(manifest, registry, cfCmsVersion) {
    const results = [
      this.validateManifest(manifest),
      this.validateSecurity(manifest),
      this.validateDependencies(manifest, registry),
      this.validateCompatibility(manifest, cfCmsVersion)
    ];
    return {
      valid: results.every((r) => r.valid),
      errors: results.flatMap((r) => r.errors),
      warnings: results.flatMap((r) => r.warnings)
    };
  }
  /**
   * Validate plugin can be uninstalled
   */
  validateForUninstallation(pluginId, registry) {
    const errors = [];
    const warnings = [];
    const dependents = registry.getAll().filter((p) => p.dependencies && p.dependencies[pluginId]);
    if (dependents.length > 0) {
      errors.push(
        `Cannot uninstall: ${dependents.map((p) => p.name).join(", ")} depend on this plugin`
      );
    }
    return { valid: errors.length === 0, errors, warnings };
  }
};
function isValidSemver(version) {
  const semverRegex = /^\d+\.\d+\.\d+(-[a-zA-Z0-9.]+)?(\+[a-zA-Z0-9.]+)?$/;
  return semverRegex.test(version);
}

// src/plugins/hook-system.ts
var HookSystem = class {
  hooks = /* @__PURE__ */ new Map();
  errorHandlers = [];
  /**
   * Register a hook handler
   */
  register(hookName, handler, priority = 10, pluginId = "core") {
    if (!this.hooks.has(hookName)) {
      this.hooks.set(hookName, []);
    }
    const hookList = this.hooks.get(hookName);
    hookList.push({ name: hookName, handler, priority, pluginId });
    hookList.sort((a, b) => a.priority - b.priority);
  }
  /**
   * Execute all handlers for a hook
   */
  async execute(hookName, data, context) {
    const hookList = this.hooks.get(hookName);
    if (!hookList || hookList.length === 0) {
      return data;
    }
    let result = data;
    for (const hook of hookList) {
      try {
        const hookContext = {
          plugin: hook.pluginId,
          context: context || {}
        };
        result = await hook.handler(result, hookContext);
        if (hookContext.cancel) {
          break;
        }
      } catch (error) {
        this.handleError(error, hookName);
      }
    }
    return result;
  }
  /**
   * Execute hooks in parallel (for non-modifying hooks)
   */
  async executeParallel(hookName, data, context) {
    const hookList = this.hooks.get(hookName);
    if (!hookList || hookList.length === 0) {
      return [];
    }
    const promises = hookList.map(async (hook) => {
      try {
        const hookContext = {
          plugin: hook.pluginId,
          context: context || {}
        };
        return await hook.handler(data, hookContext);
      } catch (error) {
        this.handleError(error, hookName);
        return null;
      }
    });
    return Promise.all(promises);
  }
  /**
   * Unregister a hook handler
   */
  unregister(hookName, handler) {
    const hookList = this.hooks.get(hookName);
    if (!hookList) return;
    const index = hookList.findIndex((h) => h.handler === handler);
    if (index !== -1) {
      hookList.splice(index, 1);
    }
  }
  /**
   * Unregister all hooks for a plugin
   */
  unregisterPlugin(pluginId) {
    for (const [, hookList] of this.hooks) {
      const index = hookList.findIndex((h) => h.pluginId === pluginId);
      if (index !== -1) {
        hookList.splice(index, 1);
      }
    }
  }
  /**
   * Get all registered hooks for a name
   */
  getHooks(hookName) {
    return this.hooks.get(hookName) || [];
  }
  /**
   * Get all hooks
   */
  getAllHooks() {
    return new Map(this.hooks);
  }
  /**
   * Register error handler
   */
  onError(handler) {
    this.errorHandlers.push(handler);
  }
  /**
   * Handle hook execution error
   */
  handleError(error, hookName) {
    console.error(`[HookSystem] Error in hook ${hookName}:`, error);
    for (const handler of this.errorHandlers) {
      try {
        handler(error, hookName);
      } catch (e) {
        console.error("[HookSystem] Error in error handler:", e);
      }
    }
  }
  /**
   * Create a scoped hook system for a plugin
   */
  createScope(pluginId) {
    return new ScopedHookSystem(this, pluginId);
  }
};
var ScopedHookSystem = class {
  constructor(parent, pluginId) {
    this.parent = parent;
    this.pluginId = pluginId;
  }
  registeredHooks = [];
  /**
   * Register a hook handler
   */
  register(hookName, handler, priority = 10) {
    this.parent.register(hookName, handler, priority, this.pluginId);
    this.registeredHooks.push({ hookName, handler, priority });
  }
  /**
   * Execute a hook
   */
  async execute(hookName, data, context) {
    return this.parent.execute(hookName, data, context);
  }
  /**
   * Unregister a hook handler
   */
  unregister(hookName, handler) {
    this.parent.unregister(hookName, handler);
    const index = this.registeredHooks.findIndex(
      (h) => h.hookName === hookName && h.handler === handler
    );
    if (index !== -1) {
      this.registeredHooks.splice(index, 1);
    }
  }
  /**
   * Unregister all hooks for this plugin
   */
  unregisterAll() {
    for (const hook of this.registeredHooks) {
      this.parent.unregister(hook.hookName, hook.handler);
    }
    this.registeredHooks = [];
  }
};
var STANDARD_HOOKS = {
  // Application lifecycle
  APP_INIT: "app:init",
  APP_READY: "app:ready",
  APP_SHUTDOWN: "app:shutdown",
  // Request lifecycle
  REQUEST_START: "request:start",
  REQUEST_END: "request:end",
  REQUEST_ERROR: "request:error",
  // Authentication
  AUTH_LOGIN: "auth:login",
  AUTH_LOGOUT: "auth:logout",
  AUTH_REGISTER: "auth:register",
  // Content lifecycle
  CONTENT_BEFORE_CREATE: "content:before:create",
  CONTENT_AFTER_CREATE: "content:after:create",
  CONTENT_BEFORE_UPDATE: "content:before:update",
  CONTENT_AFTER_UPDATE: "content:after:update",
  CONTENT_BEFORE_DELETE: "content:before:delete",
  CONTENT_AFTER_DELETE: "content:after:delete",
  CONTENT_BEFORE_PUBLISH: "content:before:publish",
  CONTENT_AFTER_PUBLISH: "content:after:publish",
  // Media lifecycle
  MEDIA_BEFORE_UPLOAD: "media:before:upload",
  MEDIA_AFTER_UPLOAD: "media:after:upload",
  MEDIA_BEFORE_DELETE: "media:before:delete",
  MEDIA_AFTER_DELETE: "media:after:delete",
  // Plugin lifecycle
  PLUGIN_BEFORE_INSTALL: "plugin:before:install",
  PLUGIN_AFTER_INSTALL: "plugin:after:install",
  PLUGIN_BEFORE_UNINSTALL: "plugin:before:uninstall",
  PLUGIN_AFTER_UNINSTALL: "plugin:after:uninstall",
  PLUGIN_BEFORE_ACTIVATE: "plugin:before:activate",
  PLUGIN_AFTER_ACTIVATE: "plugin:after:activate",
  PLUGIN_BEFORE_DEACTIVATE: "plugin:before:deactivate",
  PLUGIN_AFTER_DEACTIVATE: "plugin:after:deactivate",
  // Admin interface
  ADMIN_MENU_RENDER: "admin:menu:render",
  ADMIN_PAGE_RENDER: "admin:page:render",
  ADMIN_DASHBOARD_RENDER: "admin:dashboard:render",
  // Database
  DB_BEFORE_MIGRATE: "db:before:migrate",
  DB_AFTER_MIGRATE: "db:after:migrate",
  DB_BEFORE_SEED: "db:before:seed",
  DB_AFTER_SEED: "db:after:seed"
};

// src/plugins/route-registry.ts
var RouteRegistry = class {
  db;
  routes = /* @__PURE__ */ new Map();
  routesByPlugin = /* @__PURE__ */ new Map();
  app = null;
  constructor(options) {
    this.db = options.db;
  }
  /**
   * Set the Hono app instance for route registration
   */
  setApp(app) {
    this.app = app;
  }
  /**
   * Register a route
   */
  async registerRoute(pluginId, path, method, handler, options) {
    for (const route2 of this.routes.values()) {
      if (route2.method === method && route2.path === path && route2.pluginId !== pluginId) {
        throw new Error(
          `Route conflict: ${method} ${path} already registered by ${route2.pluginId}`
        );
      }
    }
    const routeId = `${pluginId}:${method}:${path}`;
    const route = {
      id: routeId,
      pluginId,
      path,
      method,
      handler,
      middleware: options?.middleware,
      requiresAuth: options?.requiresAuth,
      permissions: options?.permissions,
      active: true
    };
    this.routes.set(routeId, route);
    if (!this.routesByPlugin.has(pluginId)) {
      this.routesByPlugin.set(pluginId, []);
    }
    this.routesByPlugin.get(pluginId).push(routeId);
    if (this.app) {
      this.registerWithApp(route);
    }
    await this.db.prepare(`
        INSERT OR REPLACE INTO plugin_routes 
        (id, plugin_id, path, method, handler_name, is_active)
        VALUES (?, ?, ?, ?, ?, ?)
      `).bind(routeId, pluginId, path, method, handler.name || "handler", true).run();
  }
  /**
   * Unregister a route
   */
  async unregisterRoute(routeId) {
    const route = this.routes.get(routeId);
    if (!route) return;
    this.routes.delete(routeId);
    const pluginRoutes = this.routesByPlugin.get(route.pluginId);
    if (pluginRoutes) {
      const index = pluginRoutes.indexOf(routeId);
      if (index !== -1) {
        pluginRoutes.splice(index, 1);
      }
    }
    await this.db.prepare("UPDATE plugin_routes SET is_active = ? WHERE id = ?").bind(false, routeId).run();
  }
  /**
   * Unregister all routes for a plugin
   */
  async unregisterPluginRoutes(pluginId) {
    const routeIds = this.routesByPlugin.get(pluginId) || [];
    for (const routeId of routeIds) {
      await this.unregisterRoute(routeId);
    }
    this.routesByPlugin.delete(pluginId);
  }
  /**
   * Get a route
   */
  getRoute(routeId) {
    return this.routes.get(routeId);
  }
  /**
   * Get all routes
   */
  getAllRoutes() {
    return Array.from(this.routes.values());
  }
  /**
   * Get routes for a plugin
   */
  getPluginRoutes(pluginId) {
    const routeIds = this.routesByPlugin.get(pluginId) || [];
    return routeIds.map((id) => this.routes.get(id)).filter(Boolean);
  }
  /**
   * Get active routes
   */
  getActiveRoutes() {
    return Array.from(this.routes.values()).filter((r) => r.active);
  }
  /**
   * Enable a route
   */
  async enableRoute(routeId) {
    const route = this.routes.get(routeId);
    if (!route) return;
    route.active = true;
    await this.db.prepare("UPDATE plugin_routes SET is_active = ? WHERE id = ?").bind(true, routeId).run();
  }
  /**
   * Disable a route
   */
  async disableRoute(routeId) {
    const route = this.routes.get(routeId);
    if (!route) return;
    route.active = false;
    await this.db.prepare("UPDATE plugin_routes SET is_active = ? WHERE id = ?").bind(false, routeId).run();
  }
  /**
   * Register route with Hono app
   */
  registerWithApp(route) {
    if (!this.app) return;
    const wrappedHandler = async (c) => {
      if (route.middleware) {
        for (const mw of route.middleware) {
          await mw(c, async () => {
          });
        }
      }
      return route.handler(c);
    };
    switch (route.method) {
      case "GET":
        this.app.get(route.path, wrappedHandler);
        break;
      case "POST":
        this.app.post(route.path, wrappedHandler);
        break;
      case "PUT":
        this.app.put(route.path, wrappedHandler);
        break;
      case "DELETE":
        this.app.delete(route.path, wrappedHandler);
        break;
      case "PATCH":
        this.app.patch(route.path, wrappedHandler);
        break;
    }
  }
  /**
   * Load routes from database
   */
  async loadFromDatabase() {
    try {
      const result = await this.db.prepare("SELECT * FROM plugin_routes WHERE is_active = ?").bind(true).all();
      if (result.results) {
        for (const row of result.results) {
        }
      }
    } catch (error) {
      console.error("[RouteRegistry] Failed to load routes from database:", error);
    }
  }
};

// src/plugins/admin-ui-registry.ts
var AdminUIRegistry = class {
  db;
  pages = /* @__PURE__ */ new Map();
  menuItems = /* @__PURE__ */ new Map();
  extensions = /* @__PURE__ */ new Map();
  pagesByPlugin = /* @__PURE__ */ new Map();
  menuItemsByPlugin = /* @__PURE__ */ new Map();
  extensionsByPlugin = /* @__PURE__ */ new Map();
  constructor(options) {
    this.db = options.db;
  }
  /**
   * Register an admin page
   */
  async registerPage(pluginId, path, title, component, options) {
    const pageId = `${pluginId}:${path}`;
    const page = {
      id: pageId,
      pluginId,
      path,
      title,
      icon: options?.icon,
      description: options?.description,
      permissions: options?.permissions,
      component,
      active: true
    };
    if (options?.menuItem) {
      const menuItemId = `${pluginId}:menu:${path}`;
      const menuItem = {
        id: menuItemId,
        label: options.menuItem.label,
        path: options.menuItem.path || path,
        icon: options.menuItem.icon,
        order: options.menuItem.order,
        parent: options.menuItem.parent,
        permissions: options.menuItem.permissions,
        active: true
      };
      this.menuItems.set(menuItemId, menuItem);
      if (!this.menuItemsByPlugin.has(pluginId)) {
        this.menuItemsByPlugin.set(pluginId, []);
      }
      this.menuItemsByPlugin.get(pluginId).push(menuItemId);
      page.menuItem = menuItem;
    }
    this.pages.set(pageId, page);
    if (!this.pagesByPlugin.has(pluginId)) {
      this.pagesByPlugin.set(pluginId, []);
    }
    this.pagesByPlugin.get(pluginId).push(pageId);
    await this.db.prepare(`
        INSERT OR REPLACE INTO admin_pages 
        (id, plugin_id, path, title, icon, description, permissions, component, active)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
      `).bind(
      pageId,
      pluginId,
      path,
      title,
      options?.icon || null,
      options?.description || null,
      options?.permissions ? JSON.stringify(options.permissions) : null,
      component,
      true
    ).run();
  }
  /**
   * Register a menu item
   */
  async registerMenuItem(pluginId, label, path, options) {
    const menuItemId = `${pluginId}:menu:${path}`;
    const menuItem = {
      id: menuItemId,
      label,
      path,
      icon: options?.icon,
      order: options?.order,
      parent: options?.parent,
      permissions: options?.permissions,
      active: true
    };
    this.menuItems.set(menuItemId, menuItem);
    if (!this.menuItemsByPlugin.has(pluginId)) {
      this.menuItemsByPlugin.set(pluginId, []);
    }
    this.menuItemsByPlugin.get(pluginId).push(menuItemId);
    await this.db.prepare(`
        INSERT OR REPLACE INTO admin_menu_items 
        (id, plugin_id, label, path, icon, order_index, parent, permissions, active)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
      `).bind(
      menuItemId,
      pluginId,
      label,
      path,
      options?.icon || null,
      options?.order || 100,
      options?.parent || null,
      options?.permissions ? JSON.stringify(options.permissions) : null,
      true
    ).run();
  }
  /**
   * Register a UI extension point
   */
  async registerExtension(pluginId, extensionPoint, component, order) {
    const extensionId = `${pluginId}:ext:${extensionPoint}`;
    const extension = {
      id: extensionId,
      pluginId,
      extensionPoint,
      component,
      order: order || 100,
      active: true
    };
    this.extensions.set(extensionId, extension);
    if (!this.extensionsByPlugin.has(pluginId)) {
      this.extensionsByPlugin.set(pluginId, []);
    }
    this.extensionsByPlugin.get(pluginId).push(extensionId);
    await this.db.prepare(`
        INSERT OR REPLACE INTO admin_extensions 
        (id, plugin_id, extension_point, component, order_index, active)
        VALUES (?, ?, ?, ?, ?, ?)
      `).bind(extensionId, pluginId, extensionPoint, component, order || 100, true).run();
  }
  /**
   * Unregister all admin UI elements for a plugin
   */
  async unregisterPlugin(pluginId) {
    const pageIds = this.pagesByPlugin.get(pluginId) || [];
    for (const pageId of pageIds) {
      this.pages.delete(pageId);
    }
    this.pagesByPlugin.delete(pluginId);
    const menuItemIds = this.menuItemsByPlugin.get(pluginId) || [];
    for (const menuItemId of menuItemIds) {
      this.menuItems.delete(menuItemId);
    }
    this.menuItemsByPlugin.delete(pluginId);
    const extensionIds = this.extensionsByPlugin.get(pluginId) || [];
    for (const extensionId of extensionIds) {
      this.extensions.delete(extensionId);
    }
    this.extensionsByPlugin.delete(pluginId);
    await this.db.prepare("UPDATE admin_pages SET active = ? WHERE plugin_id = ?").bind(false, pluginId).run();
    await this.db.prepare("UPDATE admin_menu_items SET active = ? WHERE plugin_id = ?").bind(false, pluginId).run();
    await this.db.prepare("UPDATE admin_extensions SET active = ? WHERE plugin_id = ?").bind(false, pluginId).run();
  }
  /**
   * Get all admin pages
   */
  getPages() {
    return Array.from(this.pages.values()).filter((p) => p.active);
  }
  /**
   * Get pages for a plugin
   */
  getPluginPages(pluginId) {
    const pageIds = this.pagesByPlugin.get(pluginId) || [];
    return pageIds.map((id) => this.pages.get(id)).filter((p) => p && p.active);
  }
  /**
   * Get all menu items
   */
  getMenuItems() {
    return Array.from(this.menuItems.values()).filter((m) => m.active);
  }
  /**
   * Get menu items for a plugin
   */
  getPluginMenuItems(pluginId) {
    const menuItemIds = this.menuItemsByPlugin.get(pluginId) || [];
    return menuItemIds.map((id) => this.menuItems.get(id)).filter((m) => m && m.active);
  }
  /**
   * Get extensions for an extension point
   */
  getExtensions(extensionPoint) {
    return Array.from(this.extensions.values()).filter((e) => e.extensionPoint === extensionPoint && e.active).sort((a, b) => (a.order || 100) - (b.order || 100));
  }
  /**
   * Get all extensions
   */
  getAllExtensions() {
    return Array.from(this.extensions.values()).filter((e) => e.active);
  }
  /**
   * Render menu HTML
   */
  renderMenu(userPermissions = []) {
    const items = this.getMenuItems().filter((item) => {
      if (!item.permissions || item.permissions.length === 0) return true;
      return item.permissions.some((p) => userPermissions.includes(p));
    }).sort((a, b) => (a.order || 100) - (b.order || 100));
    let html = '<ul class="admin-menu">';
    for (const item of items) {
      html += `
        <li class="admin-menu-item">
          <a href="${item.path}" class="admin-menu-link">
            ${item.icon ? `<span class="icon">${item.icon}</span>` : ""}
            <span class="label">${item.label}</span>
          </a>
        </li>
      `;
    }
    html += "</ul>";
    return html;
  }
  /**
   * Load from database
   */
  async loadFromDatabase() {
    try {
      const pagesResult = await this.db.prepare("SELECT * FROM admin_pages WHERE active = ?").bind(true).all();
      if (pagesResult.results) {
        for (const row of pagesResult.results) {
          const page = {
            id: row.id,
            pluginId: row.plugin_id,
            path: row.path,
            title: row.title,
            icon: row.icon,
            description: row.description,
            permissions: row.permissions ? JSON.parse(row.permissions) : void 0,
            component: row.component,
            active: true
          };
          this.pages.set(page.id, page);
        }
      }
      const menuResult = await this.db.prepare("SELECT * FROM admin_menu_items WHERE active = ?").bind(true).all();
      if (menuResult.results) {
        for (const row of menuResult.results) {
          const menuItem = {
            id: row.id,
            label: row.label,
            path: row.path,
            icon: row.icon,
            order: row.order_index,
            parent: row.parent,
            permissions: row.permissions ? JSON.parse(row.permissions) : void 0,
            active: true
          };
          this.menuItems.set(menuItem.id, menuItem);
        }
      }
      const extResult = await this.db.prepare("SELECT * FROM admin_extensions WHERE active = ?").bind(true).all();
      if (extResult.results) {
        for (const row of extResult.results) {
          const extension = {
            id: row.id,
            pluginId: row.plugin_id,
            extensionPoint: row.extension_point,
            component: row.component,
            order: row.order_index,
            active: true
          };
          this.extensions.set(extension.id, extension);
        }
      }
    } catch (error) {
      console.error("[AdminUIRegistry] Failed to load from database:", error);
    }
  }
};

// src/plugins/plugin-manager.ts
var PluginManager = class {
  db;
  kv;
  r2;
  cfCmsVersion;
  registry;
  validator;
  hooks;
  routes;
  adminUI;
  loadedPlugins = /* @__PURE__ */ new Map();
  pluginContexts = /* @__PURE__ */ new Map();
  constructor(options) {
    this.db = options.db;
    this.kv = options.kv;
    this.r2 = options.r2;
    this.cfCmsVersion = options.cfCmsVersion;
    this.registry = new PluginRegistry({ db: this.db });
    this.validator = new PluginValidator();
    this.hooks = new HookSystem();
    this.routes = new RouteRegistry({ db: this.db });
    this.adminUI = new AdminUIRegistry({ db: this.db });
  }
  /**
   * Initialize plugin system
   */
  async initialize() {
    console.log("[PluginManager] Initializing plugin system...");
    try {
      await this.registry.initialize();
      await this.adminUI.loadFromDatabase();
      await this.routes.loadFromDatabase();
      await this.hooks.execute(STANDARD_HOOKS.APP_INIT, {});
      console.log("[PluginManager] Plugin system initialized successfully");
    } catch (error) {
      console.error("[PluginManager] Failed to initialize:", error);
      throw error;
    }
  }
  /**
   * Load plugins in dependency order
   */
  async loadPlugins() {
    console.log("[PluginManager] Loading plugins...");
    const { order, errors } = this.registry.resolveLoadOrder();
    if (errors.length > 0) {
      console.error("[PluginManager] Plugin dependency errors:", errors);
    }
    for (const pluginId of order) {
      try {
        await this.loadPlugin(pluginId);
      } catch (error) {
        console.error(`[PluginManager] Failed to load plugin ${pluginId}:`, error);
        await this.registry.markError(pluginId, String(error));
      }
    }
    await this.hooks.execute(STANDARD_HOOKS.APP_READY, {});
    console.log("[PluginManager] Plugins loaded successfully");
  }
  /**
   * Load a single plugin
   */
  async loadPlugin(pluginId) {
    const manifest = this.registry.get(pluginId);
    if (!manifest) throw new Error(`Plugin not found: ${pluginId}`);
    if (manifest.status !== "active") {
      console.log(`[PluginManager] Skipping inactive plugin: ${pluginId}`);
      return;
    }
    if (this.loadedPlugins.has(pluginId)) {
      console.log(`[PluginManager] Plugin already loaded: ${pluginId}`);
      return;
    }
    console.log(`[PluginManager] Loading plugin: ${pluginId}`);
    try {
      const context = this.createPluginContext(manifest);
      this.pluginContexts.set(pluginId, context);
      await this.hooks.execute(STANDARD_HOOKS.PLUGIN_BEFORE_ACTIVATE, { pluginId });
      const plugin = this.loadedPlugins.get(pluginId);
      if (!plugin) {
        throw new Error(`Plugin module not found: ${pluginId}`);
      }
      if (plugin.activate) {
        await plugin.activate(context);
      }
      if (plugin.routes) {
        for (const route of plugin.routes) {
          await this.routes.registerRoute(
            pluginId,
            route.path,
            route.method || "GET",
            route.handler,
            {
              middleware: route.middleware,
              requiresAuth: route.requiresAuth,
              permissions: route.permissions
            }
          );
        }
      }
      if (plugin.hooks) {
        const scopedHooks = this.hooks.createScope(pluginId);
        for (const hook of plugin.hooks) {
          scopedHooks.register(hook.name, hook.handler, hook.priority);
        }
      }
      if (plugin.adminPages) {
        for (const page of plugin.adminPages) {
          await this.adminUI.registerPage(
            pluginId,
            page.path,
            page.title,
            page.component,
            {
              icon: page.icon,
              description: page.description,
              permissions: page.permissions,
              menuItem: page.menuItem
            }
          );
        }
      }
      await this.hooks.execute(STANDARD_HOOKS.PLUGIN_AFTER_ACTIVATE, { pluginId });
      console.log(`[PluginManager] Plugin loaded successfully: ${pluginId}`);
    } catch (error) {
      console.error(`[PluginManager] Error loading plugin ${pluginId}:`, error);
      await this.registry.markError(pluginId, String(error));
      throw error;
    }
  }
  /**
   * Install a plugin
   */
  async installPlugin(manifest, path, entry) {
    console.log(`[PluginManager] Installing plugin: ${manifest.id}`);
    try {
      const validation = this.validator.validateForInstallation(
        manifest,
        this.registry,
        this.cfCmsVersion
      );
      if (!validation.valid) {
        throw new Error(`Plugin validation failed: ${validation.errors.join(", ")}`);
      }
      await this.hooks.execute(STANDARD_HOOKS.PLUGIN_BEFORE_INSTALL, { manifest });
      await this.registry.register(manifest, path, entry);
      await this.hooks.execute(STANDARD_HOOKS.PLUGIN_AFTER_INSTALL, { manifest });
      console.log(`[PluginManager] Plugin installed successfully: ${manifest.id}`);
    } catch (error) {
      console.error(`[PluginManager] Failed to install plugin:`, error);
      throw error;
    }
  }
  /**
   * Uninstall a plugin
   */
  async uninstallPlugin(pluginId) {
    console.log(`[PluginManager] Uninstalling plugin: ${pluginId}`);
    try {
      const validation = this.validator.validateForUninstallation(pluginId, this.registry);
      if (!validation.valid) {
        throw new Error(`Cannot uninstall: ${validation.errors.join(", ")}`);
      }
      await this.hooks.execute(STANDARD_HOOKS.PLUGIN_BEFORE_UNINSTALL, { pluginId });
      await this.registry.deactivate(pluginId);
      await this.routes.unregisterPluginRoutes(pluginId);
      await this.adminUI.unregisterPlugin(pluginId);
      this.hooks.unregisterPlugin(pluginId);
      const plugin = this.loadedPlugins.get(pluginId);
      if (plugin && plugin.uninstall) {
        const context = this.pluginContexts.get(pluginId);
        if (context) {
          await plugin.uninstall(context);
        }
      }
      await this.registry.unregister(pluginId);
      this.loadedPlugins.delete(pluginId);
      this.pluginContexts.delete(pluginId);
      await this.hooks.execute(STANDARD_HOOKS.PLUGIN_AFTER_UNINSTALL, { pluginId });
      console.log(`[PluginManager] Plugin uninstalled successfully: ${pluginId}`);
    } catch (error) {
      console.error(`[PluginManager] Failed to uninstall plugin:`, error);
      throw error;
    }
  }
  /**
   * Activate a plugin
   */
  async activatePlugin(pluginId) {
    await this.registry.activate(pluginId);
    await this.loadPlugin(pluginId);
  }
  /**
   * Deactivate a plugin
   */
  async deactivatePlugin(pluginId) {
    await this.hooks.execute(STANDARD_HOOKS.PLUGIN_BEFORE_DEACTIVATE, { pluginId });
    const plugin = this.loadedPlugins.get(pluginId);
    if (plugin && plugin.deactivate) {
      const context = this.pluginContexts.get(pluginId);
      if (context) {
        await plugin.deactivate(context);
      }
    }
    await this.routes.unregisterPluginRoutes(pluginId);
    this.hooks.unregisterPlugin(pluginId);
    await this.registry.deactivate(pluginId);
    await this.hooks.execute(STANDARD_HOOKS.PLUGIN_AFTER_DEACTIVATE, { pluginId });
  }
  /**
   * Register a loaded plugin
   */
  registerLoadedPlugin(pluginId, plugin) {
    this.loadedPlugins.set(pluginId, plugin);
  }
  /**
   * Create plugin context
   */
  createPluginContext(manifest) {
    const pluginId = manifest.id;
    const scopedHooks = this.hooks.createScope(pluginId);
    return {
      db: this.db,
      kv: this.kv,
      r2: this.r2,
      config: {},
      services: {
        auth: {},
        content: {},
        media: {}
      },
      hooks: scopedHooks,
      logger: {
        debug: (msg, data) => console.debug(`[${pluginId}] ${msg}`, data),
        info: (msg, data) => console.info(`[${pluginId}] ${msg}`, data),
        warn: (msg, data) => console.warn(`[${pluginId}] ${msg}`, data),
        error: (msg, err, data) => console.error(`[${pluginId}] ${msg}`, err, data)
      }
    };
  }
  /**
   * Get plugin status
   */
  getPluginStatus(pluginId) {
    return this.registry.getStatus(pluginId);
  }
  /**
   * Get all plugin statuses
   */
  getAllPluginStatuses() {
    return this.registry.getAllStatuses();
  }
};

export { AdminUIRegistry, HookSystem, PluginManager, PluginManifestSchema, PluginRegistry, PluginValidator, RouteRegistry, STANDARD_HOOKS, ScopedHookSystem, resolvePluginLoadOrder, validateDependencies, validateManifest };
//# sourceMappingURL=chunk-MXGIR5ZS.js.map
//# sourceMappingURL=chunk-MXGIR5ZS.js.map