const appliers = /* @__PURE__ */ new Map();
const warnedUnwiredDomains = /* @__PURE__ */ new Set();
function registerModuleOverrideApplier(domain, applier) {
  appliers.set(domain, applier);
}
function resetModuleOverrideAppliersForTests() {
  appliers.clear();
  warnedUnwiredDomains.clear();
  registerBuiltInModuleOverrideAppliers();
}
const DOMAIN_KEYS = [
  "ai",
  "routes",
  "events",
  "workers",
  "widgets",
  "notifications",
  "interceptors",
  "commandInterceptors",
  "enrichers",
  "guards",
  "cli",
  "setup",
  "acl",
  "di",
  "encryption",
  "nav"
];
const TRACKING_ISSUE_HINT = "See `.ai/specs/implemented/2026-05-04-modules-ts-unified-overrides.md` and tracking issue https://github.com/open-mercato/open-mercato/issues/1787.";
function applyModuleOverridesFromEnabledModules(modules) {
  if (!Array.isArray(modules) || modules.length === 0) return;
  const buckets = /* @__PURE__ */ new Map();
  for (const entry of modules) {
    if (!entry || typeof entry.id !== "string" || !entry.id) continue;
    const overrides = entry.overrides;
    if (!overrides || typeof overrides !== "object") continue;
    for (const domain of DOMAIN_KEYS) {
      const value = overrides[domain];
      if (value === void 0 || value === null) continue;
      if (typeof value !== "object") continue;
      const list = buckets.get(domain) ?? [];
      list.push({ moduleId: entry.id, overrides: value });
      buckets.set(domain, list);
    }
  }
  for (const [domain, entries] of buckets) {
    const applier = appliers.get(domain);
    if (!applier) {
      if (!warnedUnwiredDomains.has(domain)) {
        warnedUnwiredDomains.add(domain);
        const moduleIds = Array.from(new Set(entries.map((e) => e.moduleId))).join(", ");
        logger.warn("Override domain not yet wired \u2014 entry ignored", { domain, moduleIds, hint: TRACKING_ISSUE_HINT });
      }
      continue;
    }
    applier(entries);
  }
}
import { createLogger } from "../lib/logger/index.js";
import { resolveDeclaredPageRouteMetadata } from "./pageRouteMetadata.js";
const logger = createLogger("shared").child({ component: "module-overrides" });
const pageRouteOverrideStore = { modules: {}, programmatic: {} };
const subscriberOverrideStore = { modules: {}, programmatic: {} };
const workerOverrideStore = { modules: {}, programmatic: {} };
const cliOverrideStore = { modules: {}, programmatic: {} };
const injectionWidgetOverrideStore = { modules: {}, programmatic: {} };
const dashboardWidgetOverrideStore = { modules: {}, programmatic: {} };
const componentOverrideStore = { modules: {}, programmatic: {} };
const notificationTypeOverrideStore = { modules: {}, programmatic: {} };
const notificationHandlerOverrideStore = { modules: {}, programmatic: {} };
const apiInterceptorOverrideStore = { modules: {}, programmatic: {} };
const commandInterceptorOverrideStore = { modules: {}, programmatic: {} };
const responseEnricherOverrideStore = { modules: {}, programmatic: {} };
const pageGuardOverrideStore = { modules: {}, programmatic: {} };
const aclFeatureOverrideStore = { modules: {}, programmatic: {} };
const encryptionMapOverrideStore = { modules: {}, programmatic: {} };
const diOverrideStore = { modules: {}, programmatic: {} };
const setupOverridesByModule = {};
const GLOBAL_NAV_OVERRIDE_STATE_KEY = "__openMercatoNavOverrideState__";
function getNavOverrideState() {
  const existing = globalThis[GLOBAL_NAV_OVERRIDE_STATE_KEY];
  if (existing && typeof existing === "object") {
    const typed = existing;
    if ("modules" in typed && "programmatic" in typed) return typed;
  }
  const initial = { modules: null, programmatic: null };
  globalThis[GLOBAL_NAV_OVERRIDE_STATE_KEY] = initial;
  return initial;
}
function normalizeNavGroupOrder(value) {
  if (!Array.isArray(value)) return null;
  const ids = Array.from(
    new Set(
      value.filter((id) => typeof id === "string" && id.trim().length > 0).map((id) => id.trim())
    )
  );
  return ids.length > 0 ? ids : null;
}
function applyNavGroupOrderOverrides(groupOrder) {
  getNavOverrideState().programmatic = groupOrder === null ? null : normalizeNavGroupOrder(groupOrder);
}
function getNavGroupOrderOverride() {
  const state = getNavOverrideState();
  return state.programmatic ?? state.modules?.groupOrder ?? null;
}
function normalizeIdOverrideKey(key, label) {
  if (typeof key !== "string") return null;
  const trimmed = key.trim();
  if (trimmed) return trimmed;
  logger.warn("Skipping malformed override key \u2014 expected a non-empty string", { label, key });
  return null;
}
function clearStore(store) {
  for (const key of Object.keys(store.modules)) delete store.modules[key];
  for (const key of Object.keys(store.programmatic)) delete store.programmatic[key];
}
const EMPTY_OVERRIDE_MAP = Object.freeze({});
function applyStoreOverrides(store, target, overrides, options) {
  if (!overrides || typeof overrides !== "object") return;
  const normalize = options.normalizeKey ?? ((key) => normalizeIdOverrideKey(key, options.label));
  for (const [rawKey, value] of Object.entries(overrides)) {
    const key = normalize(rawKey);
    if (!key) continue;
    store[target][key] = value;
  }
}
function composeStore(store) {
  const modulesKeys = Object.keys(store.modules);
  const programmaticKeys = Object.keys(store.programmatic);
  if (modulesKeys.length === 0 && programmaticKeys.length === 0) {
    return EMPTY_OVERRIDE_MAP;
  }
  return { ...store.modules, ...store.programmatic };
}
function applyArrayOverrides(items, overrides, options) {
  if (!items || Object.keys(overrides).length === 0) {
    return { items: items ? Array.from(items) : items, consumed: /* @__PURE__ */ new Set(), changed: false };
  }
  const consumed = /* @__PURE__ */ new Set();
  const result = [];
  let changed = false;
  for (const item of items) {
    const id = options.getId(item);
    if (!id || !Object.prototype.hasOwnProperty.call(overrides, id)) {
      result.push(item);
      continue;
    }
    consumed.add(id);
    changed = true;
    const replacement = overrides[id];
    if (replacement === null) continue;
    if (options.isReplacement && !options.isReplacement(replacement)) {
      logger.warn("Skipping malformed override \u2014 replacement has the wrong shape", { label: options.label, id });
      result.push(item);
      continue;
    }
    const replacementId = options.getId(replacement);
    if (replacementId !== id) {
      logger.warn("Skipping malformed override \u2014 replacement id must match the override key", { label: options.label, id });
      result.push(item);
      continue;
    }
    result.push(replacement);
  }
  return { items: result, consumed, changed };
}
function warnStaleOverrides(label, overrides, consumed) {
  for (const key of Object.keys(overrides)) {
    if (!consumed.has(key)) {
      logger.warn("Override did not match any registered entry \u2014 override skipped", { label, key });
    }
  }
}
function isObjectWithId(value) {
  return !!value && typeof value === "object" && typeof value.id === "string";
}
function isModuleSubscriber(value) {
  return isObjectWithId(value) && typeof value.event === "string" && typeof value.handler === "function";
}
function isModuleWorker(value) {
  return isObjectWithId(value) && typeof value.queue === "string" && typeof value.handler === "function";
}
function isModuleCli(value) {
  return !!value && typeof value === "object" && typeof value.command === "string" && typeof value.run === "function";
}
function isInjectionWidgetEntry(value) {
  return !!value && typeof value === "object" && typeof value.key === "string" && typeof value.loader === "function";
}
function isDashboardWidgetEntry(value) {
  return !!value && typeof value === "object" && typeof value.key === "string" && typeof value.loader === "function";
}
function isComponentOverrideValue(value) {
  const items = Array.isArray(value) ? value : [value];
  return items.every(
    (item) => !!item && typeof item === "object" && !!item.target && typeof item.target.componentId === "string"
  );
}
function isNotificationType(value) {
  return !!value && typeof value === "object" && typeof value.type === "string";
}
function isNotificationHandler(value) {
  return isObjectWithId(value) && typeof value.handle === "function";
}
function isApiInterceptor(value) {
  return isObjectWithId(value) && typeof value.targetRoute === "string";
}
function isCommandInterceptor(value) {
  return isObjectWithId(value) && typeof value.targetCommand === "string";
}
function isResponseEnricher(value) {
  return isObjectWithId(value) && typeof value.targetEntity === "string" && typeof value.enrichOne === "function";
}
function isPageRouteMiddleware(value) {
  return isObjectWithId(value) && typeof value.run === "function";
}
function isEncryptionMap(value) {
  return !!value && typeof value === "object" && typeof value.entityId === "string" && Array.isArray(value.fields);
}
function getFeatureId(value) {
  if (typeof value === "string" && value.trim()) return value.trim();
  if (value && typeof value === "object" && typeof value.id === "string") {
    return value.id;
  }
  return null;
}
const VALID_HTTP_METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
const programmaticApiRouteOverrides = {};
const modulesConfigApiRouteOverrides = {};
function normalizeApiRouteOverrideKey(key) {
  if (typeof key !== "string") return null;
  const trimmed = key.trim();
  if (!trimmed) return null;
  const parts = trimmed.split(/\s+/);
  if (parts.length < 2) return null;
  const method = parts[0].toUpperCase();
  if (!VALID_HTTP_METHODS.includes(method)) return null;
  const rawPath = parts.slice(1).join(" ").trim();
  if (!rawPath) return null;
  const withLead = rawPath.startsWith("/") ? rawPath : `/${rawPath}`;
  const normalized = withLead.replace(/\/+$/, "") || "/";
  return `${method} ${normalized}`;
}
function normalizePageRouteOverrideKey(key) {
  if (typeof key !== "string") return null;
  const trimmed = key.trim();
  if (!trimmed) return null;
  if (trimmed.startsWith("backend:") || trimmed.startsWith("frontend:")) return trimmed;
  const withLead = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
  const stripped = withLead.replace(/\/+$/, "") || "/";
  if (stripped === "/frontend") return "frontend:/";
  if (stripped.startsWith("/frontend/")) return `frontend:/${stripped.slice("/frontend/".length)}`;
  if (stripped === "/backend" || stripped.startsWith("/backend/")) return `backend:${stripped}`;
  return `frontend:${stripped}`;
}
function applyApiRouteOverrides(overrides) {
  if (!overrides) return;
  for (const [rawKey, value] of Object.entries(overrides)) {
    const key = normalizeApiRouteOverrideKey(rawKey);
    if (!key) {
      logger.warn('Skipping malformed routes.api key \u2014 expected "METHOD /api/path"', { key: rawKey });
      continue;
    }
    programmaticApiRouteOverrides[key] = value;
  }
}
function resetApiRouteOverridesForTests() {
  for (const key of Object.keys(programmaticApiRouteOverrides)) {
    delete programmaticApiRouteOverrides[key];
  }
  for (const key of Object.keys(modulesConfigApiRouteOverrides)) {
    delete modulesConfigApiRouteOverrides[key];
  }
}
function resetModuleContractOverridesForTests() {
  resetApiRouteOverridesForTests();
  clearStore(pageRouteOverrideStore);
  clearStore(subscriberOverrideStore);
  clearStore(workerOverrideStore);
  clearStore(cliOverrideStore);
  clearStore(injectionWidgetOverrideStore);
  clearStore(dashboardWidgetOverrideStore);
  clearStore(componentOverrideStore);
  clearStore(notificationTypeOverrideStore);
  clearStore(notificationHandlerOverrideStore);
  clearStore(apiInterceptorOverrideStore);
  clearStore(commandInterceptorOverrideStore);
  clearStore(responseEnricherOverrideStore);
  clearStore(pageGuardOverrideStore);
  clearStore(aclFeatureOverrideStore);
  clearStore(encryptionMapOverrideStore);
  clearStore(diOverrideStore);
  for (const key of Object.keys(setupOverridesByModule)) delete setupOverridesByModule[key];
  const navState = getNavOverrideState();
  navState.modules = null;
  navState.programmatic = null;
}
function composeApiRouteOverrides() {
  const modulesKeys = Object.keys(modulesConfigApiRouteOverrides);
  const programmaticKeys = Object.keys(programmaticApiRouteOverrides);
  if (modulesKeys.length === 0 && programmaticKeys.length === 0) {
    return EMPTY_OVERRIDE_MAP;
  }
  const out = {};
  for (const k of modulesKeys) out[k] = modulesConfigApiRouteOverrides[k];
  for (const k of programmaticKeys) out[k] = programmaticApiRouteOverrides[k];
  return out;
}
function applyPageRouteOverrides(overrides) {
  applyStoreOverrides(pageRouteOverrideStore, "programmatic", overrides, {
    label: "routes.pages",
    normalizeKey: normalizePageRouteOverrideKey
  });
}
function composePageRouteOverrides() {
  return composeStore(pageRouteOverrideStore);
}
function applySubscriberOverrides(overrides) {
  applyStoreOverrides(subscriberOverrideStore, "programmatic", overrides, { label: "events.subscribers" });
}
function composeSubscriberOverrides() {
  return composeStore(subscriberOverrideStore);
}
function applyWorkerOverrides(overrides) {
  applyStoreOverrides(workerOverrideStore, "programmatic", overrides, { label: "workers" });
}
function composeWorkerOverrides() {
  return composeStore(workerOverrideStore);
}
function applyCliOverrides(overrides) {
  applyStoreOverrides(cliOverrideStore, "programmatic", overrides, { label: "cli" });
}
function composeCliOverrides() {
  return composeStore(cliOverrideStore);
}
function applyInjectionWidgetOverrides(overrides) {
  applyStoreOverrides(injectionWidgetOverrideStore, "programmatic", overrides, { label: "widgets.injection" });
}
function composeInjectionWidgetOverrides() {
  return composeStore(injectionWidgetOverrideStore);
}
function applyDashboardWidgetOverrides(overrides) {
  applyStoreOverrides(dashboardWidgetOverrideStore, "programmatic", overrides, { label: "widgets.dashboard" });
}
function composeDashboardWidgetOverrides() {
  return composeStore(dashboardWidgetOverrideStore);
}
function applyComponentOverrides(overrides) {
  applyStoreOverrides(componentOverrideStore, "programmatic", overrides, { label: "widgets.components" });
}
function composeComponentOverrides() {
  return composeStore(componentOverrideStore);
}
function applyNotificationTypeOverrides(overrides) {
  applyStoreOverrides(notificationTypeOverrideStore, "programmatic", overrides, { label: "notifications.types" });
}
function composeNotificationTypeOverrides() {
  return composeStore(notificationTypeOverrideStore);
}
function applyNotificationHandlerOverrides(overrides) {
  applyStoreOverrides(notificationHandlerOverrideStore, "programmatic", overrides, { label: "notifications.handlers" });
}
function composeNotificationHandlerOverrides() {
  return composeStore(notificationHandlerOverrideStore);
}
function applyApiInterceptorOverrides(overrides) {
  applyStoreOverrides(apiInterceptorOverrideStore, "programmatic", overrides, { label: "interceptors" });
}
function composeApiInterceptorOverrides() {
  return composeStore(apiInterceptorOverrideStore);
}
function applyCommandInterceptorOverrides(overrides) {
  applyStoreOverrides(commandInterceptorOverrideStore, "programmatic", overrides, { label: "commandInterceptors" });
}
function composeCommandInterceptorOverrides() {
  return composeStore(commandInterceptorOverrideStore);
}
function applyResponseEnricherOverrides(overrides) {
  applyStoreOverrides(responseEnricherOverrideStore, "programmatic", overrides, { label: "enrichers" });
}
function composeResponseEnricherOverrides() {
  return composeStore(responseEnricherOverrideStore);
}
function applyPageGuardOverrides(overrides) {
  applyStoreOverrides(pageGuardOverrideStore, "programmatic", overrides, { label: "guards" });
}
function composePageGuardOverrides() {
  return composeStore(pageGuardOverrideStore);
}
function applyAclFeatureOverrides(overrides) {
  applyStoreOverrides(aclFeatureOverrideStore, "programmatic", overrides, { label: "acl.features" });
}
function composeAclFeatureOverrides() {
  return composeStore(aclFeatureOverrideStore);
}
function applyEncryptionMapOverrides(overrides) {
  applyStoreOverrides(encryptionMapOverrideStore, "programmatic", overrides, { label: "encryption.maps" });
}
function composeEncryptionMapOverrides() {
  return composeStore(encryptionMapOverrideStore);
}
function applyDiOverrides(overrides) {
  applyStoreOverrides(diOverrideStore, "programmatic", overrides, { label: "di" });
}
function composeDiOverrides() {
  return composeStore(diOverrideStore);
}
function applyApiOverridesToManifests(routes, overrides) {
  if (!routes || routes.length === 0) return Array.from(routes);
  const overrideKeys = Object.keys(overrides);
  if (overrideKeys.length === 0) return Array.from(routes);
  const consumedKeys = /* @__PURE__ */ new Set();
  const result = [];
  for (const entry of routes) {
    const path = entry.path;
    const remainingMethods = [];
    const methodOverrides = /* @__PURE__ */ new Map();
    for (const method of entry.methods) {
      const manifestKey = `${method} ${path}`;
      const publicKey = path.startsWith("/api/") ? manifestKey : `${method} /api${path === "/" ? "" : path}`;
      const key = Object.prototype.hasOwnProperty.call(overrides, manifestKey) ? manifestKey : Object.prototype.hasOwnProperty.call(overrides, publicKey) ? publicKey : null;
      if (!key) {
        remainingMethods.push(method);
        continue;
      }
      consumedKeys.add(key);
      const value = overrides[key];
      if (value === null) continue;
      if (value && typeof value === "object" && typeof value.handler === "function") {
        methodOverrides.set(method, value);
        remainingMethods.push(method);
      } else {
        logger.warn("Skipping malformed routes.api override \u2014 expected { handler, metadata? } or null", { key });
        remainingMethods.push(method);
      }
    }
    if (remainingMethods.length === 0) continue;
    const methodsChanged = remainingMethods.length !== entry.methods.length;
    const hasReplacements = methodOverrides.size > 0;
    if (!methodsChanged && !hasReplacements) {
      result.push(entry);
      continue;
    }
    const originalLoad = entry.load;
    const wrappedLoad = hasReplacements ? async () => {
      const original = await originalLoad();
      const out = { ...original };
      const baseMetadata = original && typeof original === "object" && original.metadata !== void 0 ? original.metadata : null;
      const mergedMetadata = baseMetadata && typeof baseMetadata === "object" ? { ...baseMetadata } : {};
      for (const [method, def] of methodOverrides) {
        out[method] = def.handler;
        if (def.metadata !== void 0) mergedMetadata[method] = def.metadata;
      }
      if (Object.keys(mergedMetadata).length > 0) out.metadata = mergedMetadata;
      return out;
    } : originalLoad;
    result.push({ ...entry, methods: remainingMethods, load: wrappedLoad });
  }
  for (const key of overrideKeys) {
    if (!consumedKeys.has(key)) {
      logger.warn("routes.api override did not match any registered API route \u2014 override skipped", { key });
    }
  }
  return result;
}
function applyPageOverridesToManifests(routes, overrides, kind) {
  if (!routes || routes.length === 0) return Array.from(routes);
  const normalizedOverrides = {};
  for (const [rawKey, value] of Object.entries(overrides)) {
    const key = normalizePageRouteOverrideKey(rawKey);
    if (!key) {
      logger.warn('Skipping malformed routes.pages key \u2014 expected "/backend/path" or "/frontend/path"', { key: rawKey });
      continue;
    }
    normalizedOverrides[key] = value;
  }
  const overrideKeys = Object.keys(normalizedOverrides).filter((key) => key.startsWith(`${kind}:`));
  if (overrideKeys.length === 0) return Array.from(routes);
  const consumed = /* @__PURE__ */ new Set();
  const result = [];
  for (const entry of routes) {
    const path = entry.pattern ?? entry.path ?? "/";
    const key = `${kind}:${path.replace(/\/+$/, "") || "/"}`;
    if (!Object.prototype.hasOwnProperty.call(normalizedOverrides, key)) {
      result.push(entry);
      continue;
    }
    consumed.add(key);
    const override = normalizedOverrides[key];
    if (override === null) continue;
    if (!override || typeof override !== "object") {
      logger.warn("Skipping malformed routes.pages override \u2014 expected { load?, Component?, metadata? } or null", { key });
      result.push(entry);
      continue;
    }
    const hasLoad = typeof override.load === "function";
    const hasComponent = typeof override.Component === "function";
    if (!hasLoad && !hasComponent && override.metadata === void 0) {
      logger.warn("Skipping malformed routes.pages override \u2014 expected a loader, component, metadata, or null", { key });
      result.push(entry);
      continue;
    }
    const metadata = override.metadata && typeof override.metadata === "object" ? override.metadata : {};
    const load = hasLoad ? override.load : hasComponent ? async () => override.Component : entry.load;
    result.push({ ...entry, ...metadata, ...resolveDeclaredPageRouteMetadata(metadata), load });
  }
  warnStaleOverrides("routes.pages", Object.fromEntries(
    overrideKeys.map((key) => [key, normalizedOverrides[key]])
  ), consumed);
  return result;
}
function applyEntryListOverrides(entries, overrides, options) {
  if (!entries || Object.keys(overrides).length === 0) return entries;
  const consumed = /* @__PURE__ */ new Set();
  let changed = false;
  const result = entries.map((entry) => {
    const list = entry[options.listKey];
    if (!Array.isArray(list)) return entry;
    const applied = applyArrayOverrides(list, overrides, {
      label: options.label,
      getId: options.getId,
      isReplacement: options.isReplacement
    });
    for (const key of applied.consumed) consumed.add(key);
    if (!applied.changed) return entry;
    changed = true;
    return { ...entry, [options.listKey]: applied.items ?? [] };
  });
  warnStaleOverrides(options.label, overrides, consumed);
  return changed ? result : Array.from(entries);
}
function applyInjectionWidgetOverridesToEntries(entries, overrides = composeInjectionWidgetOverrides()) {
  const applied = applyArrayOverrides(entries, overrides, {
    label: "widgets.injection",
    getId: (entry) => entry.key,
    isReplacement: isInjectionWidgetEntry
  });
  warnStaleOverrides("widgets.injection", overrides, applied.consumed);
  return applied.items ?? [];
}
function applyDashboardWidgetOverridesToEntries(entries, overrides = composeDashboardWidgetOverrides()) {
  const applied = applyArrayOverrides(entries, overrides, {
    label: "widgets.dashboard",
    getId: (entry) => entry.key,
    isReplacement: isDashboardWidgetEntry
  });
  warnStaleOverrides("widgets.dashboard", overrides, applied.consumed);
  return applied.items ?? [];
}
function applyWorkerOverridesToDescriptors(entries, overrides = composeWorkerOverrides()) {
  const applied = applyArrayOverrides(entries, overrides, {
    label: "workers",
    getId: (entry) => entry.id,
    isReplacement: (value) => !!value && typeof value === "object" && typeof value.id === "string" && typeof value.queue === "string" && typeof value.concurrency === "number" && typeof value.handler === "function"
  });
  warnStaleOverrides("workers", overrides, applied.consumed);
  return applied.items ?? [];
}
function applyInjectionWidgetOverridesToTables(tables, overrides = composeInjectionWidgetOverrides()) {
  const disabled = new Set(Object.entries(overrides).filter(([, value]) => value === null).map(([key]) => key));
  if (disabled.size === 0) return Array.from(tables);
  const filterSlot = (slot) => {
    if (typeof slot === "string") return disabled.has(slot) ? null : slot;
    if (slot && typeof slot === "object") {
      const widgetId = slot.widgetId;
      return typeof widgetId === "string" && disabled.has(widgetId) ? null : slot;
    }
    return slot;
  };
  return tables.map((entry) => {
    const nextTable = {};
    for (const [spotId, rawSlot] of Object.entries(entry.table)) {
      const filtered = Array.isArray(rawSlot) ? rawSlot.map(filterSlot).filter((slot) => slot !== null) : filterSlot(rawSlot);
      if (Array.isArray(filtered)) {
        if (filtered.length > 0) nextTable[spotId] = filtered;
      } else if (filtered !== null) {
        nextTable[spotId] = filtered;
      }
    }
    return { ...entry, table: nextTable };
  });
}
function applyComponentOverridesToEntries(entries, overrides = composeComponentOverrides()) {
  const overrideKeys = Object.keys(overrides);
  if (overrideKeys.length === 0) return Array.from(entries);
  const consumed = /* @__PURE__ */ new Set();
  const additions = [];
  const result = entries.map((entry) => {
    const next = entry.componentOverrides.filter((override) => {
      const id = override.target.componentId;
      if (!Object.prototype.hasOwnProperty.call(overrides, id)) return true;
      consumed.add(id);
      return false;
    });
    return { ...entry, componentOverrides: next };
  });
  for (const key of overrideKeys) {
    const value = overrides[key];
    if (value === null) continue;
    if (!isComponentOverrideValue(value)) {
      logger.warn("Skipping malformed widgets.components override \u2014 expected ComponentOverride, ComponentOverride[], or null", { key });
      continue;
    }
    const values = Array.isArray(value) ? value : [value];
    for (const override of values) {
      if (override.target.componentId !== key) {
        logger.warn("Skipping malformed widgets.components override \u2014 target.componentId must match the override key", { key });
        continue;
      }
      additions.push(override);
      consumed.add(key);
    }
  }
  if (additions.length > 0) {
    result.push({ moduleId: "overrides", componentOverrides: additions });
  }
  warnStaleOverrides("widgets.components", overrides, consumed);
  return result;
}
function applyNotificationTypeOverridesToEntries(entries, overrides = composeNotificationTypeOverrides()) {
  return applyEntryListOverrides(entries, overrides, {
    listKey: "types",
    label: "notifications.types",
    getId: (entry) => entry.type,
    isReplacement: isNotificationType
  }) ?? [];
}
function applyNotificationHandlerOverridesToEntries(entries, overrides = composeNotificationHandlerOverrides()) {
  return applyEntryListOverrides(entries, overrides, {
    listKey: "handlers",
    label: "notifications.handlers",
    getId: (entry) => entry.id,
    isReplacement: isNotificationHandler
  }) ?? [];
}
function applyApiInterceptorOverridesToEntries(entries, overrides = composeApiInterceptorOverrides()) {
  return applyEntryListOverrides(entries, overrides, {
    listKey: "interceptors",
    label: "interceptors",
    getId: (entry) => entry.id,
    isReplacement: isApiInterceptor
  }) ?? [];
}
function applyCommandInterceptorOverridesToEntries(entries, overrides = composeCommandInterceptorOverrides()) {
  return applyEntryListOverrides(entries, overrides, {
    listKey: "interceptors",
    label: "commandInterceptors",
    getId: (entry) => entry.id,
    isReplacement: isCommandInterceptor
  }) ?? [];
}
function applyResponseEnricherOverridesToEntries(entries, overrides = composeResponseEnricherOverrides()) {
  return applyEntryListOverrides(entries, overrides, {
    listKey: "enrichers",
    label: "enrichers",
    getId: (entry) => entry.id,
    isReplacement: isResponseEnricher
  }) ?? [];
}
function applyPageGuardOverridesToEntries(entries, overrides = composePageGuardOverrides()) {
  return applyEntryListOverrides(entries, overrides, {
    listKey: "middleware",
    label: "guards",
    getId: (entry) => entry.id,
    isReplacement: isPageRouteMiddleware
  }) ?? [];
}
function applySetupOverride(setup, override) {
  if (!override) return setup;
  const next = { ...setup ?? {} };
  if (override.defaultRoleFeatures) {
    next.defaultRoleFeatures = Object.fromEntries(
      Object.entries(override.defaultRoleFeatures).map(([role, features]) => [role, Array.from(features)])
    );
  }
  if (override.defaultCustomerRoleFeatures) {
    next.defaultCustomerRoleFeatures = Object.fromEntries(
      Object.entries(override.defaultCustomerRoleFeatures).map(([role, features]) => [role, Array.from(features)])
    );
  }
  if (override.seedDefaults === false) delete next.seedDefaults;
  if (override.seedExamples === false) delete next.seedExamples;
  if (override.onTenantCreated === false) delete next.onTenantCreated;
  return next;
}
function applyModuleOverridesToModules(modules) {
  const subscriberOverrides = composeSubscriberOverrides();
  const workerOverrides = composeWorkerOverrides();
  const cliOverrides = composeCliOverrides();
  const aclOverrides = composeAclFeatureOverrides();
  const encryptionOverrides = composeEncryptionMapOverrides();
  const hasSetupOverrides = Object.keys(setupOverridesByModule).length > 0;
  const hasAny = Object.keys(subscriberOverrides).length > 0 || Object.keys(workerOverrides).length > 0 || Object.keys(cliOverrides).length > 0 || Object.keys(aclOverrides).length > 0 || Object.keys(encryptionOverrides).length > 0 || hasSetupOverrides;
  if (!hasAny) return modules;
  const subscriberConsumed = /* @__PURE__ */ new Set();
  const workerConsumed = /* @__PURE__ */ new Set();
  const cliConsumed = /* @__PURE__ */ new Set();
  const aclConsumed = /* @__PURE__ */ new Set();
  const encryptionConsumed = /* @__PURE__ */ new Set();
  const result = modules.map((module) => {
    let next = module;
    const subscribers = applyArrayOverrides(module.subscribers, subscriberOverrides, {
      label: "events.subscribers",
      getId: (entry) => entry.id,
      isReplacement: isModuleSubscriber
    });
    for (const key of subscribers.consumed) subscriberConsumed.add(key);
    if (subscribers.changed) next = { ...next, subscribers: subscribers.items };
    const workers = applyArrayOverrides(module.workers, workerOverrides, {
      label: "workers",
      getId: (entry) => entry.id,
      isReplacement: isModuleWorker
    });
    for (const key of workers.consumed) workerConsumed.add(key);
    if (workers.changed) next = { ...next, workers: workers.items };
    const cli = applyArrayOverrides(module.cli, cliOverrides, {
      label: "cli",
      getId: (entry) => entry.command,
      isReplacement: isModuleCli
    });
    for (const key of cli.consumed) cliConsumed.add(key);
    if (cli.changed) next = { ...next, cli: cli.items };
    const features = applyArrayOverrides(module.features, aclOverrides, {
      label: "acl.features",
      getId: getFeatureId,
      isReplacement: (value) => getFeatureId(value) !== null
    });
    for (const key of features.consumed) aclConsumed.add(key);
    if (features.changed) next = { ...next, features: features.items };
    const maps = applyArrayOverrides(module.defaultEncryptionMaps, encryptionOverrides, {
      label: "encryption.maps",
      getId: (entry) => entry.entityId,
      isReplacement: isEncryptionMap
    });
    for (const key of maps.consumed) encryptionConsumed.add(key);
    if (maps.changed) next = { ...next, defaultEncryptionMaps: maps.items };
    const setupOverride = setupOverridesByModule[module.id];
    if (setupOverride) {
      next = { ...next, setup: applySetupOverride(module.setup, setupOverride) };
    }
    return next;
  });
  warnStaleOverrides("events.subscribers", subscriberOverrides, subscriberConsumed);
  warnStaleOverrides("workers", workerOverrides, workerConsumed);
  warnStaleOverrides("cli", cliOverrides, cliConsumed);
  warnStaleOverrides("acl.features", aclOverrides, aclConsumed);
  warnStaleOverrides("encryption.maps", encryptionOverrides, encryptionConsumed);
  return result;
}
function applyDiOverridesToContainer(container) {
  const overrides = composeDiOverrides();
  for (const [key, value] of Object.entries(overrides)) {
    if (value === null) {
      if (typeof container.unregister === "function") {
        container.unregister(key);
      } else if (container.registrations && key in container.registrations) {
        delete container.registrations[key];
      }
      continue;
    }
    if (value && typeof value === "object" && typeof value.register === "function") {
      ;
      value.register(container, key);
      continue;
    }
    container.register({ [key]: value });
  }
}
function routesOverridesApplier(entries) {
  for (const entry of entries) {
    const shape = entry.overrides;
    if (!shape || typeof shape !== "object") continue;
    const api = shape.api;
    if (api && typeof api === "object") {
      for (const [rawKey, value] of Object.entries(api)) {
        const key = normalizeApiRouteOverrideKey(rawKey);
        if (!key) {
          logger.warn('Skipping malformed routes.api key \u2014 expected "METHOD /api/path"', { key: rawKey });
          continue;
        }
        modulesConfigApiRouteOverrides[key] = value;
      }
    }
    const pages = shape.pages;
    if (pages && typeof pages === "object" && Object.keys(pages).length > 0) {
      applyStoreOverrides(pageRouteOverrideStore, "modules", pages, {
        label: "routes.pages",
        normalizeKey: normalizePageRouteOverrideKey
      });
    }
  }
}
function eventsOverridesApplier(entries) {
  for (const entry of entries) {
    const subscribers = entry.overrides?.subscribers;
    applyStoreOverrides(subscriberOverrideStore, "modules", subscribers, { label: "events.subscribers" });
  }
}
function workersOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(workerOverrideStore, "modules", entry.overrides, { label: "workers" });
  }
}
function widgetsOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(injectionWidgetOverrideStore, "modules", entry.overrides?.injection, { label: "widgets.injection" });
    applyStoreOverrides(componentOverrideStore, "modules", entry.overrides?.components, { label: "widgets.components" });
    applyStoreOverrides(dashboardWidgetOverrideStore, "modules", entry.overrides?.dashboard, { label: "widgets.dashboard" });
  }
}
function notificationsOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(notificationTypeOverrideStore, "modules", entry.overrides?.types, { label: "notifications.types" });
    applyStoreOverrides(notificationHandlerOverrideStore, "modules", entry.overrides?.handlers, { label: "notifications.handlers" });
  }
}
function interceptorsOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(apiInterceptorOverrideStore, "modules", entry.overrides, { label: "interceptors" });
  }
}
function commandInterceptorsOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(commandInterceptorOverrideStore, "modules", entry.overrides, { label: "commandInterceptors" });
  }
}
function enrichersOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(responseEnricherOverrideStore, "modules", entry.overrides, { label: "enrichers" });
  }
}
function guardsOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(pageGuardOverrideStore, "modules", entry.overrides, { label: "guards" });
  }
}
function cliOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(cliOverrideStore, "modules", entry.overrides, { label: "cli" });
  }
}
function setupOverridesApplier(entries) {
  for (const entry of entries) {
    if (!entry.overrides || typeof entry.overrides !== "object") continue;
    setupOverridesByModule[entry.moduleId] = entry.overrides;
  }
}
function aclOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(aclFeatureOverrideStore, "modules", entry.overrides?.features, { label: "acl.features" });
  }
}
function diOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(diOverrideStore, "modules", entry.overrides, { label: "di" });
  }
}
function encryptionOverridesApplier(entries) {
  for (const entry of entries) {
    applyStoreOverrides(encryptionMapOverrideStore, "modules", entry.overrides?.maps, { label: "encryption.maps" });
  }
}
function navOverridesApplier(entries) {
  const state = getNavOverrideState();
  for (const entry of entries) {
    const groupOrder = normalizeNavGroupOrder(entry.overrides?.groupOrder);
    if (!groupOrder) continue;
    if (state.modules && state.modules.moduleId !== entry.moduleId) {
      logger.warn("nav.groupOrder declared by more than one module \u2014 the later one wins", {
        previousModuleId: state.modules.moduleId,
        moduleId: entry.moduleId,
        hint: "Sidebar group ordering is a single app-wide decision; declare it on one module entry."
      });
    }
    state.modules = { moduleId: entry.moduleId, groupOrder };
  }
}
function registerBuiltInModuleOverrideAppliers() {
  registerModuleOverrideApplier("nav", navOverridesApplier);
  registerModuleOverrideApplier("routes", routesOverridesApplier);
  registerModuleOverrideApplier("events", eventsOverridesApplier);
  registerModuleOverrideApplier("workers", workersOverridesApplier);
  registerModuleOverrideApplier("widgets", widgetsOverridesApplier);
  registerModuleOverrideApplier("notifications", notificationsOverridesApplier);
  registerModuleOverrideApplier("interceptors", interceptorsOverridesApplier);
  registerModuleOverrideApplier("commandInterceptors", commandInterceptorsOverridesApplier);
  registerModuleOverrideApplier("enrichers", enrichersOverridesApplier);
  registerModuleOverrideApplier("guards", guardsOverridesApplier);
  registerModuleOverrideApplier("cli", cliOverridesApplier);
  registerModuleOverrideApplier("setup", setupOverridesApplier);
  registerModuleOverrideApplier("acl", aclOverridesApplier);
  registerModuleOverrideApplier("di", diOverridesApplier);
  registerModuleOverrideApplier("encryption", encryptionOverridesApplier);
}
registerBuiltInModuleOverrideAppliers();
export {
  applyAclFeatureOverrides,
  applyApiInterceptorOverrides,
  applyApiInterceptorOverridesToEntries,
  applyApiOverridesToManifests,
  applyApiRouteOverrides,
  applyCliOverrides,
  applyCommandInterceptorOverrides,
  applyCommandInterceptorOverridesToEntries,
  applyComponentOverrides,
  applyComponentOverridesToEntries,
  applyDashboardWidgetOverrides,
  applyDashboardWidgetOverridesToEntries,
  applyDiOverrides,
  applyDiOverridesToContainer,
  applyEncryptionMapOverrides,
  applyInjectionWidgetOverrides,
  applyInjectionWidgetOverridesToEntries,
  applyInjectionWidgetOverridesToTables,
  applyModuleOverridesFromEnabledModules,
  applyModuleOverridesToModules,
  applyNavGroupOrderOverrides,
  applyNotificationHandlerOverrides,
  applyNotificationHandlerOverridesToEntries,
  applyNotificationTypeOverrides,
  applyNotificationTypeOverridesToEntries,
  applyPageGuardOverrides,
  applyPageGuardOverridesToEntries,
  applyPageOverridesToManifests,
  applyPageRouteOverrides,
  applyResponseEnricherOverrides,
  applyResponseEnricherOverridesToEntries,
  applySubscriberOverrides,
  applyWorkerOverrides,
  applyWorkerOverridesToDescriptors,
  composeAclFeatureOverrides,
  composeApiInterceptorOverrides,
  composeApiRouteOverrides,
  composeCliOverrides,
  composeCommandInterceptorOverrides,
  composeComponentOverrides,
  composeDashboardWidgetOverrides,
  composeDiOverrides,
  composeEncryptionMapOverrides,
  composeInjectionWidgetOverrides,
  composeNotificationHandlerOverrides,
  composeNotificationTypeOverrides,
  composePageGuardOverrides,
  composePageRouteOverrides,
  composeResponseEnricherOverrides,
  composeSubscriberOverrides,
  composeWorkerOverrides,
  getNavGroupOrderOverride,
  registerModuleOverrideApplier,
  resetApiRouteOverridesForTests,
  resetModuleContractOverridesForTests,
  resetModuleOverrideAppliersForTests
};
//# sourceMappingURL=overrides.js.map
