import { createEveCommandIntent, emptyState, renderEveSurface, } from "../packages/eve-browser-lowering/dist/index.js"; import { compileEveDsl } from "./eve-dsl.js"; const statusEl = document.querySelector("#status"); const app = document.querySelector("#app"); const surfaceId = document.querySelector("#surface-id"); const surfaceVersion = document.querySelector("#surface-version"); const providerSelect = document.querySelector("#provider-select"); const providerMeta = document.querySelector("#provider-meta"); let providers = []; let currentProvider; let liveHermodr = false; let openProviderGeneration = 0; const localProviders = [ { providerId: "repixelizer", title: "Repixelizer", kind: "service.product", advertisement: "./fixtures/repixelizer.provider-advertisement.json", surfaces: [{ transport: "local-json", surfaceId: "repixelizer.operator.surface", url: "./fixtures/repixelizer.eve-surface.json" }], }, { providerId: "fensalir.direct2d", title: "Fensalir Direct2D", kind: "surface.renderer", freshness: { state: "fixture" }, surfaces: [{ transport: "local-json", surfaceId: "fensalir.direct2d.fixture", url: "./fixtures/fensalir-client-surface.json" }], }, { providerId: "sai.visual_novel", aliases: ["gamecult.home.vn", "sai-vn"], title: "Sai VN Surface", kind: "content.runtime", freshness: { state: "fixture" }, surfaces: [{ transport: "local-json", surfaceId: "sai.visual_novel.surface", url: "./fixtures/sai-vn-surface.json" }], }, { providerId: "cultcache.huginn.inspector", title: "Huginn .cc", kind: "inspection.huginn", freshness: { state: "fixture" }, surfaces: [{ transport: "local-eve-dsl", surfaceId: "cultcache.huginn.inspector", url: "./fixtures/huginn-cc-surface.eve" }], }, { providerId: "eve.reactive.dsl", title: "Reactive DSL", kind: "surface.fixture", freshness: { state: "fixture" }, surfaces: [{ transport: "local-eve-dsl", surfaceId: "eve.reactive.dsl", url: "./fixtures/reactive-composition.eve" }], }, { providerId: "eve.cultui.inspector", title: "CultUI Inspector", kind: "surface.fixture", freshness: { state: "fixture" }, surfaces: [{ transport: "local-eve-dsl", surfaceId: "eve.cultui.inspector", url: "./fixtures/cultui-slider-inspector.eve" }], }, { providerId: "gamecult.eve.embedded-demo", title: "Embedded Surface Slot", kind: "surface.fixture", freshness: { state: "fixture" }, surfaces: [{ transport: "local-json", surfaceId: "gamecult.eve.embedded-demo", url: "./fixtures/cultui-embedded-surface.json" }], }, ]; providerSelect.addEventListener("change", () => { const provider = providers.find(candidate => candidate.providerId === providerSelect.value); if (provider) void openProvider(provider); }); void bootProviders(); async function bootProviders() { providers = await loadHermodrProviders(); if (providers.length) { liveHermodr = true; } else { providers = await Promise.all(localProviders.map(loadProviderAdvertisement)); } providerSelect.replaceChildren(...providers.map(provider => { const option = document.createElement("option"); option.value = provider.providerId; option.textContent = provider.title || provider.providerId; return option; })); const requestedProviderId = new URLSearchParams(location.search).get("provider"); const firstProduct = providers.find(provider => provider.providerId === requestedProviderId || provider.aliases?.includes(requestedProviderId)) || providers.find(provider => provider.providerId === "aetheria.main_menu.root") || providers.find(provider => provider.providerId === "aetheria.inventory.panel") || providers.find(provider => provider.providerId === "repixelizer") || providers[0]; providerSelect.value = firstProduct.providerId; await openProvider(firstProduct); } async function loadHermodrProviders() { try { const response = await fetch("/hermodr/verse/catalog", { cache: "no-store" }); if (!response.ok) return []; const catalog = await response.json(); const advertised = new Map(); for (const provider of catalog.providers || []) { advertised.set(provider.id || provider.providerId, provider); } return (catalog.surfaces || []) .filter(surface => surface?.providerId && surface?.surface) .map(surface => { const provider = advertised.get(surface.providerId) || {}; return { ...provider, providerId: surface.providerId, title: surface.title || provider.title || surface.providerId, kind: provider.kind || "eve.surface", freshness: { state: "odin-visible-cultmesh" }, surfaces: [{ transport: "hermodr-surface", surfaceId: surface.providerId, url: `/hermodr/surface/${encodeURIComponent(surface.providerId)}`, }], }; }); } catch { return []; } } async function loadProviderAdvertisement(provider) { if (!provider.advertisement) return provider; const response = await fetch(provider.advertisement); const advertisement = await response.json(); return { ...advertisement, ...provider, surfaces: provider.surfaces || advertisement.surfaces || [], localAdvertisement: advertisement, }; } async function openProvider(provider) { const generation = ++openProviderGeneration; currentProvider = provider; providerMeta.textContent = `${provider.kind || "provider"} | ${provider.providerId} | ${provider.freshness?.state || "unknown"}`; surfaceId.textContent = provider.providerId; surfaceVersion.textContent = "opening"; const surface = provider.surfaces?.[0]; if (!surface) { statusEl.textContent = `${provider.title || provider.providerId} has no advertised surface`; app.replaceChildren(emptyState("No advertised surface")); return; } if (surface.transport === "hermodr-surface") { try { const state = await fetchHermodrSurface(surface.url); if (generation !== openProviderGeneration) return; renderSurface(state, "hermodr cultmesh"); } catch (error) { if (generation !== openProviderGeneration) return; statusEl.textContent = `${provider.title || provider.providerId} failed to load`; surfaceVersion.textContent = "error"; app.replaceChildren(emptyState(error instanceof Error ? error.message : String(error))); } return; } if (surface.transport === "local-eve-dsl") { const response = await fetch(surface.url); const state = compileEveDsl(await response.text()); if (generation !== openProviderGeneration) return; renderSurface(state, "local dsl"); return; } const response = await fetch(surface.url); const state = await response.json(); if (generation !== openProviderGeneration) return; renderSurface(state, "local fixture"); } async function fetchHermodrSurface(url) { let lastError; for (let attempt = 0; attempt < 4; attempt += 1) { try { const response = await fetch(url, { cache: "no-store" }); const state = await response.json().catch(() => ({})); if (!response.ok || state?.ok === false) { throw new Error(state?.error || `Hermodr surface request failed with HTTP ${response.status}`); } if (!state?.surface?.root) { throw new Error("Hermodr returned a surface document without a root."); } return state; } catch (error) { lastError = error; await delay(250 * (attempt + 1)); } } throw lastError instanceof Error ? lastError : new Error(String(lastError)); } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function renderSurface(state, source) { surfaceId.textContent = state.providerId || "surface unknown"; surfaceVersion.textContent = `v${state.version ?? "?"}`; const providerId = state.providerId || currentProvider?.providerId || ""; renderEveSurface(state, app, { body: document.body, clientId: liveHermodr ? "hermodr.browser" : "browser.reference", commandSink: publishCommandIntent, documentResolver: liveHermodr ? createHermodrDocumentResolver(providerId) : undefined, assetUrlResolver: liveHermodr ? resolveHermodrAssetUrl : undefined, provider: currentProvider, source, statusElement: statusEl, }); } function createHermodrDocumentResolver(providerId) { return async function resolveHermodrDocument(request) { if (!providerId) return undefined; const params = new URLSearchParams(); params.set("documentId", request.documentId); if (request.schemaId) params.set("schemaId", request.schemaId); if (request.slotId) params.set("slotId", request.slotId); const response = await fetch(`/hermodr/document/${encodeURIComponent(providerId)}?${params.toString()}`, { cache: "no-store" }); if (!response.ok) throw new Error(await response.text()); return response.json(); }; } function resolveHermodrAssetUrl(uri) { if (/^(cultmesh:\/\/|resources:\/\/)/i.test(uri)) { return `/cultmesh-cdn/${encodeURIComponent(uri)}`; } return uri; } async function publishCommandIntent(intent, component) { const props = component?.props || {}; const command = intent.command ? intent : createEveCommandIntent(props.command || props.commandId || "invoke", props, { clientId: "browser.reference", provider: currentProvider, }); statusEl.textContent = `command ${command.command}`; if (!liveHermodr) { console.info("Eve command intent", command); return; } const response = await fetch("/hermodr/commands/eve", { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify(command), }); const receipt = await response.json().catch(() => ({})); if (!response.ok || receipt.ok === false) { statusEl.textContent = `command failed ${command.command}`; console.error("Eve command failed", receipt); return; } statusEl.textContent = `command accepted ${command.command}`; console.info("Eve command receipt", receipt); }