155 lines
13 KiB
TypeScript
155 lines
13 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import { readFileSync } from "node:fs";
|
|
import { dirname, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
const desktopRoot = process.env.FAMILIAROS_DESKTOP_ROOT ?? resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
const windowsSource = readFileSync(resolve(desktopRoot, "src/windows.ts"), "utf8");
|
|
const controlCenterIpcSource = readFileSync(resolve(desktopRoot, "src/control-center-ipc.ts"), "utf8");
|
|
const controlCenterIpcAgentSource = readFileSync(resolve(desktopRoot, "src/control-center-ipc-agent.ts"), "utf8");
|
|
const controlCenterIpcKnowledgeSource = readFileSync(resolve(desktopRoot, "src/control-center-ipc-knowledge.ts"), "utf8");
|
|
const controlCenterIpcPetSource = readFileSync(resolve(desktopRoot, "src/control-center-ipc-pets.ts"), "utf8");
|
|
const controlCenterIpcPluginSource = readFileSync(resolve(desktopRoot, "src/control-center-ipc-plugin.ts"), "utf8");
|
|
const controlCenterIpcSettingsSource = readFileSync(resolve(desktopRoot, "src/control-center-ipc-settings.ts"), "utf8");
|
|
const controlCenterPreloadSource = readFileSync(resolve(desktopRoot, "control-center-preload.cjs"), "utf8");
|
|
const controlCenterRendererSource = readFileSync(resolve(desktopRoot, "src/renderer/src/main.tsx"), "utf8");
|
|
const controlCenterRouteLoadersSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/route-loaders.tsx"), "utf8");
|
|
const controlCenterSharedSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/shared.tsx"), "utf8");
|
|
const controlCenterSharedUiSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/shared-ui.tsx"), "utf8");
|
|
const controlCenterSharedOpenApiSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/shared-openapi.ts"), "utf8");
|
|
const pluginsViewSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/plugins-view.tsx"), "utf8");
|
|
const pluginsViewPresentationSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/plugins-view-presentation.tsx"), "utf8");
|
|
const pluginsViewStateSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/plugins-view-state.ts"), "utf8");
|
|
const pluginsViewConfigHelpersSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/plugins-view-config-helpers.ts"), "utf8");
|
|
const pluginsViewConfigFieldsSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/plugins-view-config-fields.tsx"), "utf8");
|
|
const pluginsViewConfigListEditorSource = readFileSync(resolve(desktopRoot, "src/renderer/src/control-center/plugins-view-config-list-editor.tsx"), "utf8");
|
|
const familiarWindowSource = readFileSync(resolve(desktopRoot, "src/familiar-window.ts"), "utf8");
|
|
const familiarWindowPluginMenuSource = readFileSync(resolve(desktopRoot, "src/familiar-window-plugin-menu.ts"), "utf8");
|
|
const jsHostSource = readFileSync(resolve(desktopRoot, "src/plugin-js-host.ts"), "utf8");
|
|
const jsHostSdkDispatchSource = readFileSync(resolve(desktopRoot, "src/plugin-js-host-sdk-dispatch.ts"), "utf8");
|
|
const panelPreloadSource = readFileSync(resolve(desktopRoot, "panel-preload.cjs"), "utf8");
|
|
const pluginCommandFormPreloadSource = readFileSync(resolve(desktopRoot, "plugin-command-form-preload.cjs"), "utf8");
|
|
const pluginSdkPreloadSource = readFileSync(resolve(desktopRoot, "plugin-sdk-preload.cjs"), "utf8");
|
|
const promptWindowPreloadSource = readFileSync(resolve(desktopRoot, "prompt-window-preload.cjs"), "utf8");
|
|
const promptWindowSource = readFileSync(resolve(desktopRoot, "src/prompt-window.ts"), "utf8");
|
|
const promptWindowRenderSource = readFileSync(resolve(desktopRoot, "src/prompt-window-render.ts"), "utf8");
|
|
const promptWindowRenderScriptSource = readFileSync(resolve(desktopRoot, "src/prompt-window-render-script.ts"), "utf8");
|
|
const promptWindowRenderScriptSectionsSource = readFileSync(resolve(desktopRoot, "src/prompt-window-render-script-sections.ts"), "utf8");
|
|
const promptWindowRenderScriptInteractionsSource = readFileSync(resolve(desktopRoot, "src/prompt-window-render-script-interactions.ts"), "utf8");
|
|
const promptWindowCombinedSource = [
|
|
promptWindowSource,
|
|
promptWindowRenderSource,
|
|
promptWindowRenderScriptSource,
|
|
promptWindowRenderScriptSectionsSource,
|
|
promptWindowRenderScriptInteractionsSource,
|
|
].join("\n");
|
|
const controlCenterInternalUiSource = [
|
|
windowsSource,
|
|
controlCenterIpcSource,
|
|
controlCenterIpcAgentSource,
|
|
controlCenterIpcKnowledgeSource,
|
|
controlCenterIpcPetSource,
|
|
controlCenterIpcPluginSource,
|
|
controlCenterIpcSettingsSource,
|
|
].join("\n");
|
|
|
|
assert.doesNotMatch(windowsSource, /openTaskWindow|TaskWindowKind|createPluginsHtml|getPreloadPath|"preload\.cjs"/);
|
|
assert.match(controlCenterInternalUiSource, /assertAllowedSender\(getControlCenterWindow, event, \["control-center"\]\)/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-snapshot/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-save-config/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-load-local/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-catalog-snapshot/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-install-catalog/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-update-catalog/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-uninstall/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-load-local[\s\S]*assertAllowedSender\(getControlCenterWindow, event, \["control-center"\]\)/);
|
|
|
|
assert.match(controlCenterPreloadSource, /getPluginsSnapshot: \(\) => ipcRenderer\.invoke\("familiaros:plugins-snapshot"\)/);
|
|
assert.match(controlCenterPreloadSource, /getPluginCatalogSnapshot: \(refresh\) => ipcRenderer\.invoke\("familiaros:plugins-catalog-snapshot", refresh\)/);
|
|
assert.match(controlCenterPreloadSource, /setPluginEnabled: \(id, enabled\) => ipcRenderer\.invoke\("familiaros:plugins-set-enabled", id, enabled\)/);
|
|
assert.match(controlCenterPreloadSource, /savePluginConfig: \(id, config\) => ipcRenderer\.invoke\("familiaros:plugins-save-config", id, config\)/);
|
|
assert.match(controlCenterPreloadSource, /loadLocalPlugin: \(\) => ipcRenderer\.invoke\("familiaros:plugins-load-local"\)/);
|
|
assert.match(controlCenterPreloadSource, /installCatalogPlugin: \(id\) => ipcRenderer\.invoke\("familiaros:plugins-install-catalog", id\)/);
|
|
assert.match(controlCenterPreloadSource, /uninstallPlugin: \(id\) => ipcRenderer\.invoke\("familiaros:plugins-uninstall", id\)/);
|
|
assert.doesNotMatch(controlCenterPreloadSource, /onboarding/i);
|
|
assert.doesNotMatch(controlCenterPreloadSource, /plugins-load-local",\s*[^)]/);
|
|
assert.doesNotMatch(controlCenterPreloadSource, /manifestPath/);
|
|
assert.doesNotMatch(controlCenterPreloadSource, /installPath/);
|
|
assert.doesNotMatch(controlCenterPreloadSource, /familiaros:plugins-install-catalog",\s*[^)]+,\s*[^)]/);
|
|
|
|
assert.match(controlCenterRendererSource, /from "\.\/control-center\/route-loaders"/);
|
|
assert.match(controlCenterRendererSource, /controlCenterRouteComponents\[displayedRoute\]/);
|
|
assert.match(controlCenterRendererSource, /loadControlCenterRoute\(tab\.id\)/);
|
|
assert.match(controlCenterRendererSource, /preloadControlCenterRoutes\(navTabs\.map\(\(tab\) => tab\.id\)\)/);
|
|
assert.match(controlCenterRendererSource, /<Suspense fallback=\{<RouteLoadingState \/>}/);
|
|
assert.doesNotMatch(controlCenterRendererSource, /OnboardingView|currentRoute === "onboarding"/);
|
|
assert.match(controlCenterRouteLoadersSource, /import\("\.\/dashboard-view"\)/);
|
|
assert.match(controlCenterRouteLoadersSource, /import\("\.\/familiars-view"\)/);
|
|
assert.match(controlCenterRouteLoadersSource, /import\("\.\/settings-view"\)/);
|
|
assert.match(controlCenterRouteLoadersSource, /import\("\.\/plugins-view"\)/);
|
|
assert.match(controlCenterRouteLoadersSource, /import\("\.\/integrations-view"\)/);
|
|
assert.match(controlCenterRouteLoadersSource, /export function loadControlCenterRoute\(route: Route\)/);
|
|
assert.match(controlCenterRouteLoadersSource, /export async function preloadControlCenterRoutes\(routes: readonly Route\[]\)/);
|
|
assert.match(pluginsViewSource, /export function PluginsView\(\)/);
|
|
assert.match(pluginsViewSource, /from "\.\/plugins-view-presentation"/);
|
|
assert.match(pluginsViewSource, /from "\.\/plugins-view-state"/);
|
|
assert.match(pluginsViewSource, /from "\.\/plugins-view-config-helpers"/);
|
|
assert.match(pluginsViewSource, /from "\.\/plugins-view-config-fields"/);
|
|
assert.match(pluginsViewPresentationSource, /export function PluginIconImage/);
|
|
assert.match(pluginsViewPresentationSource, /export function pluginPrimaryLabel/);
|
|
assert.match(pluginsViewStateSource, /export function usePluginsViewState/);
|
|
assert.match(pluginsViewConfigFieldsSource, /from "\.\/plugins-view-config-list-editor"/);
|
|
assert.match(pluginsViewConfigListEditorSource, /from "\.\/plugins-view-config-helpers"/);
|
|
assert.match(pluginsViewConfigFieldsSource, /export function ConfigFieldEditor/);
|
|
assert.match(pluginsViewConfigHelpersSource, /export function materializeListItemDefaults/);
|
|
assert.match(pluginsViewStateSource, /updateCatalogEntry[\s\S]*api\.updateCatalogPlugin/);
|
|
assert.match(pluginsViewSource, /installed\.source === "catalog"[\s\S]*updateCatalogEntry/);
|
|
assert.match(controlCenterSharedSource, /export \* from "\.\/shared-ui"/);
|
|
assert.match(controlCenterSharedSource, /export \* from "\.\/shared-openapi"/);
|
|
assert.match(controlCenterSharedSource, /const api = resolveControlCenterApi\(apiBridge\);/);
|
|
assert.match(controlCenterSharedSource, /function resolveControlCenterApi\(/);
|
|
assert.match(controlCenterSharedSource, /bridge\.familiarOSControlCenter \?\? bridge\.openPetsControlCenter/);
|
|
assert.match(controlCenterSharedUiSource, /export const navTabs/);
|
|
assert.match(controlCenterSharedUiSource, /export function Button/);
|
|
assert.match(controlCenterSharedUiSource, /export function SearchInput/);
|
|
assert.match(controlCenterSharedOpenApiSource, /export const openApiEndpointPresets/);
|
|
assert.match(controlCenterSharedOpenApiSource, /export function normalizeThemeMode/);
|
|
assert.match(controlCenterSharedOpenApiSource, /export function buildPersistentToolkitBundle/);
|
|
|
|
assert.match(jsHostSource, /FamiliarOSPlugin[\s\S]*register/);
|
|
assert.match(jsHostSource, /start\(sdk\)/);
|
|
assert.match(jsHostSource, /__familiarOSRegisteredPlugin/);
|
|
assert.match(jsHostSource, /__openPetsRegisteredPlugin/);
|
|
assert.match(jsHostSource, /from "\.\/plugin-js-host-sdk-dispatch(?:\.js)?"/);
|
|
assert.match(jsHostSdkDispatchSource, /__familiarOSError/);
|
|
assert.match(jsHostSdkDispatchSource, /__familiarOSRunCallback \?\? globalThis\.__openPetsRunCallback/);
|
|
assert.match(jsHostSource, /preload: getPluginSdkPreloadPath\(\)/);
|
|
assert.match(panelPreloadSource, /contextBridge\.exposeInMainWorld\("familiarOSPanel", api\)/);
|
|
assert.match(panelPreloadSource, /contextBridge\.exposeInMainWorld\("openPetsPanel", api\)/);
|
|
assert.match(pluginCommandFormPreloadSource, /contextBridge\.exposeInMainWorld\("familiarOSCommandForm", api\)/);
|
|
assert.match(pluginCommandFormPreloadSource, /contextBridge\.exposeInMainWorld\("openPetsCommandForm", api\)/);
|
|
assert.match(promptWindowPreloadSource, /contextBridge\.exposeInMainWorld\("familiarOSPromptWindow", api\)/);
|
|
assert.match(promptWindowPreloadSource, /contextBridge\.exposeInMainWorld\("openPetsPromptWindow", api\)/);
|
|
assert.match(promptWindowRenderSource, /from "\.\/prompt-window-render-script(?:\.js)?"/);
|
|
assert.match(promptWindowRenderScriptSource, /from "\.\/prompt-window-render-script-sections(?:\.js)?"/);
|
|
assert.match(promptWindowRenderScriptSource, /from "\.\/prompt-window-render-script-interactions(?:\.js)?"/);
|
|
assert.match(promptWindowCombinedSource, /window\.familiarOSPromptWindow \|\| window\.openPetsPromptWindow/);
|
|
assert.match(familiarWindowSource, /from "\.\/familiar-window-plugin-menu(?:\.js)?"/);
|
|
assert.match(familiarWindowPluginMenuSource, /window\.familiarOSCommandForm\|\|window\.openPetsCommandForm/);
|
|
assert.match(pluginSdkPreloadSource, /__familiarOSError/);
|
|
assert.match(pluginSdkPreloadSource, /contextBridge\.exposeInMainWorld\("__familiarOSSdk", sdk\)/);
|
|
assert.match(pluginSdkPreloadSource, /contextBridge\.exposeInMainWorld\("__openPetsSdk", sdk\)/);
|
|
assert.match(pluginSdkPreloadSource, /contextBridge\.exposeInMainWorld\("__familiarOSRunCallback", runCallback\)/);
|
|
assert.match(pluginSdkPreloadSource, /contextBridge\.exposeInMainWorld\("__openPetsRunCallback", runCallback\)/);
|
|
assert.match(pluginSdkPreloadSource, /speak: \(spec\) => call\("familiar\.speak", \[petId, spec\]\)/);
|
|
assert.match(pluginSdkPreloadSource, /register: \(command, handler\) => call\("commands\.register"/);
|
|
// SDK v3 namespaces are exposed to the plugin sandbox.
|
|
assert.match(pluginSdkPreloadSource, /bubble: \(spec\) => call\("ui\.bubble", \[spec\]\)/);
|
|
assert.match(pluginSdkPreloadSource, /on: \(event, fn\) => subscription\("events\.on", "events\.off"/);
|
|
assert.match(pluginSdkPreloadSource, /publish: \(topic, payload\) => call\("bus\.publish", \[topic, payload\]\)/);
|
|
// Plugin platform settings are reachable from the Control Center.
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugin-platform-settings-get/);
|
|
assert.match(controlCenterInternalUiSource, /familiaros:plugins-inspector/);
|
|
assert.match(controlCenterPreloadSource, /getPluginPlatformSettings: \(\) => ipcRenderer\.invoke\("familiaros:plugin-platform-settings-get"\)/);
|
|
|
|
console.error("Plugin Control Center static validation passed.");
|