Files
MajoorWaldi-ComfyUI-Majoor-…/js/app/hostAdapter.js
T
Ewald f56d6284da fix: MFV popup dark theme, gen info panel, reset zoom + popout polish
- FloatingViewer.impl.js: add missing _resetMfvZoom() method (was called
  from floatingViewerLoader/Mode but never defined on the class)
- viewerShell.js: return genInfoTitle + genInfoTitleLeft from createViewerStageShell
- ViewerRuntime.js: destructure genInfoTitle + genInfoTitleLeft (were undefined
  => gen info body was never populated)
- floatingViewerPopout.js: inject document.documentElement.style.cssText as
  :root{...} in popup head so ComfyUI CSS vars are available; set body
  background to #0d0d0d; remove broken history.replaceState (Chrome blocks
  it from about:blank)
- __init__.py: remove unused FailureSeverity/StageStatus imports
2026-04-11 19:06:23 +02:00

290 lines
8.7 KiB
JavaScript

/**
* Host Adapter Layer — Majoor Assets Manager
*
* This is the SINGLE contracted boundary between Majoor application code
* (Vue components, Pinia stores, feature modules) and the ComfyUI host
* environment (DOM, ComfyUI APIs, extension manager, sidebar/panel system).
*
* Rules (see ADR 0007):
* 1. Vue components and Pinia stores MUST import host capabilities from this
* module only. Direct use of `comfyApiBridge.js` from store/component
* code is a violation.
* 2. Only `entry.js` and this file are allowed to import from
* `comfyApiBridge.js` directly.
* 3. Each method exposed here has a stable name and signature.
* The underlying ComfyUI API may change; fixes stay inside this file.
* 4. Every method is null-safe and never throws to callers.
*
* Lifecycle
* ---------
* Call `hostAdapter.init(app)` once from `entry.js` after receiving the
* ComfyUI app object. After init, all methods work correctly.
* Before init, all methods return safe no-op fallbacks.
*/
import {
activateSidebarTabCompat,
getComfyApp,
getExtensionDialogApi,
getExtensionManager,
getExtensionToastApi,
getSettingValue,
getSettingsApi,
registerBottomPanelTabCompat,
registerCommandCompat,
registerKeybindingCompat,
registerSidebarTabCompat,
setComfyApp,
waitForComfyApp,
} from "./comfyApiBridge.js";
// ── internal state ────────────────────────────────────────────────────────────
/** @type {object | null} */
let _app = null;
// ── lifecycle ─────────────────────────────────────────────────────────────────
/**
* Initialise the adapter with the ComfyUI app object.
* Must be called once from `entry.js` before any other method.
*
* @param {object} app - ComfyUI app object received in the extension setup callback.
*/
export function init(app) {
_app = setComfyApp(app) || app || null;
}
/**
* Returns true when the adapter has been initialised with a live app reference.
*/
export function isReady() {
return !!_app;
}
/**
* Wait until the host app is available (for code running before `init()`).
* Resolves with the app object or null on timeout.
*
* @param {number} [timeoutMs=5000]
* @returns {Promise<object | null>}
*/
export async function ready(timeoutMs = 5000) {
if (_app) return _app;
try {
const app = await waitForComfyApp({ timeoutMs });
if (app) _app = app;
return _app;
} catch {
return null;
}
}
// ── notifications ─────────────────────────────────────────────────────────────
/**
* Show a toast notification via ComfyUI extension manager toast.
* Falls back silently if the host API is unavailable.
*
* @param {{ severity?: "info"|"success"|"warn"|"error", summary?: string, detail?: string, life?: number }} opts
*/
export function showToast(opts) {
try {
const toastApi = getExtensionToastApi(_app || getComfyApp());
if (toastApi) {
toastApi.add({
severity: opts?.severity ?? "info",
summary: opts?.summary ?? "",
detail: opts?.detail ?? "",
life: opts?.life ?? 4000,
});
}
} catch {
// host not available — silent
}
}
// ── dialogs ───────────────────────────────────────────────────────────────────
/**
* Show a confirmation dialog.
* Returns a Promise<boolean> (true = confirmed, false = cancelled / unavailable).
*
* @param {{ message: string, header?: string }} opts
* @returns {Promise<boolean>}
*/
export async function confirm(opts) {
try {
const dialogApi = getExtensionDialogApi(_app || getComfyApp());
if (dialogApi && typeof dialogApi.confirm === "function") {
const result = await dialogApi.confirm({
message: opts?.message ?? "",
header: opts?.header ?? "Confirm",
});
return !!result;
}
} catch {
// fall through
}
return false;
}
// ── settings ──────────────────────────────────────────────────────────────────
/**
* Read a ComfyUI setting value.
*
* @param {string} key
* @param {*} [defaultValue=null]
* @returns {*}
*/
export function getSetting(key, defaultValue = null) {
try {
const value = getSettingValue(_app || getComfyApp(), key);
return value !== null && value !== undefined ? value : defaultValue;
} catch {
return defaultValue;
}
}
/**
* Get the raw ComfyUI settings API (for registration, not for reading ad-hoc values).
* Prefer `getSetting()` for reading individual settings.
*
* @returns {object | null}
*/
export function getHostSettingsApi() {
try {
return getSettingsApi(_app || getComfyApp());
} catch {
return null;
}
}
// ── sidebar & panel ───────────────────────────────────────────────────────────
/**
* Register a sidebar tab with the ComfyUI extension manager.
*
* @param {object} tabDef
* @returns {boolean} true if registration succeeded
*/
export function registerSidebarTab(tabDef) {
try {
return registerSidebarTabCompat(_app || getComfyApp(), tabDef);
} catch {
return false;
}
}
/**
* Register a bottom panel tab.
*
* @param {object} tabDef
* @returns {boolean}
*/
export function registerBottomPanelTab(tabDef) {
try {
return registerBottomPanelTabCompat(_app || getComfyApp(), tabDef);
} catch {
return false;
}
}
/**
* Programmatically activate a sidebar tab.
*
* @param {string} tabId
* @returns {boolean}
*/
export function activateSidebarTab(tabId) {
try {
return activateSidebarTabCompat(_app || getComfyApp(), tabId);
} catch {
return false;
}
}
// ── commands & keybindings ────────────────────────────────────────────────────
/**
* Register a command with the ComfyUI command palette.
*
* @param {object} commandDef
* @returns {boolean}
*/
export function registerCommand(commandDef) {
try {
return registerCommandCompat(_app || getComfyApp(), commandDef);
} catch {
return false;
}
}
/**
* Register a keybinding.
*
* @param {object} keybindingDef
* @returns {boolean}
*/
export function registerKeybinding(keybindingDef) {
try {
return registerKeybindingCompat(_app || getComfyApp(), keybindingDef);
} catch {
return false;
}
}
// ── extension manager (escape hatch) ─────────────────────────────────────────
/**
* Returns the ComfyUI extension manager object.
*
* This is an **escape hatch** for capabilities not yet wrapped above.
* Prefer adding a typed method to this adapter instead of using this.
*
* @returns {object | null}
*/
export function getHostExtensionManager() {
try {
return getExtensionManager(_app || getComfyApp());
} catch {
return null;
}
}
// ── raw app reference (escape hatch) ─────────────────────────────────────────
/**
* Returns the raw ComfyUI app reference.
*
* This is an **escape hatch**. Only use it when you need something that is
* not yet abstracted by this adapter (and then add it here).
*
* @returns {object | null}
*/
export function getRawHostApp() {
return _app || getComfyApp() || null;
}
// ── public API ────────────────────────────────────────────────────────────────
export const hostAdapter = {
init,
isReady,
ready,
showToast,
confirm,
getSetting,
getHostSettingsApi,
registerSidebarTab,
registerBottomPanelTab,
activateSidebarTab,
registerCommand,
registerKeybinding,
getHostExtensionManager,
getRawHostApp,
};
export default hostAdapter;