mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 07:16:02 +00:00
192 lines
5.3 KiB
TypeScript
192 lines
5.3 KiB
TypeScript
/**
|
|
* Extension IPC Handlers — Main Process
|
|
*
|
|
* Registers IPC handlers for extension management (discover, install,
|
|
* uninstall, enable/disable) and exposes them to the renderer via preload.
|
|
*/
|
|
|
|
import { BrowserWindow, dialog, ipcMain, shell } from "electron";
|
|
import {
|
|
discoverExtensions,
|
|
getExtension,
|
|
getExtensionsDirectory,
|
|
getRegisteredExtensions,
|
|
installExtensionFromPath,
|
|
setExtensionStatus,
|
|
uninstallExtension,
|
|
} from "./extensionLoader";
|
|
import {
|
|
downloadAndInstallExtension,
|
|
fetchPendingReviews,
|
|
getMarketplaceExtension,
|
|
searchMarketplace,
|
|
submitExtensionForReview,
|
|
updateReviewStatus,
|
|
} from "./extensionMarketplace";
|
|
import { getErrorMessage } from "./errorUtils";
|
|
import type { ExtensionInfo, MarketplaceReviewStatus } from "./extensionTypes";
|
|
|
|
/**
|
|
* Serialize extension info for IPC transfer (strip non-serializable fields).
|
|
*/
|
|
function serializeExtensionInfo(info: ExtensionInfo) {
|
|
return {
|
|
manifest: info.manifest,
|
|
status: info.status,
|
|
path: info.path,
|
|
error: info.error,
|
|
builtin: info.builtin ?? false,
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Register all extension-related IPC handlers.
|
|
* Call this once during app initialization (in main.ts).
|
|
*/
|
|
export function registerExtensionIpcHandlers(): void {
|
|
// Discover all extensions (builtin + user-installed)
|
|
ipcMain.handle("extensions:discover", async () => {
|
|
const extensions = await discoverExtensions();
|
|
return extensions.map(serializeExtensionInfo);
|
|
});
|
|
|
|
// List currently registered extensions
|
|
ipcMain.handle("extensions:list", () => {
|
|
return getRegisteredExtensions().map(serializeExtensionInfo);
|
|
});
|
|
|
|
// Get a specific extension by ID
|
|
ipcMain.handle("extensions:get", (_event, id: string) => {
|
|
const ext = getExtension(id);
|
|
return ext ? serializeExtensionInfo(ext) : null;
|
|
});
|
|
|
|
// Enable an extension
|
|
ipcMain.handle("extensions:enable", async (_event, id: string) => {
|
|
return setExtensionStatus(id, "active");
|
|
});
|
|
|
|
// Disable an extension
|
|
ipcMain.handle("extensions:disable", async (_event, id: string) => {
|
|
return setExtensionStatus(id, "disabled");
|
|
});
|
|
|
|
// Install an extension from a folder picker
|
|
ipcMain.handle("extensions:install-from-folder", async (event) => {
|
|
const window = BrowserWindow.fromWebContents(event.sender);
|
|
const result = await dialog.showOpenDialog(window!, {
|
|
title: "Select Extension Folder",
|
|
properties: ["openDirectory"],
|
|
message: "Select a folder containing a recordly-extension.json manifest",
|
|
});
|
|
|
|
if (result.canceled || result.filePaths.length === 0) {
|
|
return { success: false, reason: "cancelled" };
|
|
}
|
|
|
|
const info = await installExtensionFromPath(result.filePaths[0]);
|
|
if (!info) {
|
|
return {
|
|
success: false,
|
|
reason: "Invalid extension: missing or invalid recordly-extension.json",
|
|
};
|
|
}
|
|
|
|
return { success: true, extension: serializeExtensionInfo(info) };
|
|
});
|
|
|
|
// Uninstall an extension
|
|
ipcMain.handle("extensions:uninstall", async (_event, id: string) => {
|
|
const success = await uninstallExtension(id);
|
|
return { success };
|
|
});
|
|
|
|
// Get extensions directory path
|
|
ipcMain.handle("extensions:get-directory", () => {
|
|
return getExtensionsDirectory();
|
|
});
|
|
|
|
// Open extensions directory in file manager
|
|
ipcMain.handle("extensions:open-directory", async () => {
|
|
const dir = getExtensionsDirectory();
|
|
await shell.openPath(dir);
|
|
return { success: true };
|
|
});
|
|
|
|
// ── Marketplace ─────────────────────────────────────────────────────
|
|
|
|
// Search/browse marketplace
|
|
ipcMain.handle(
|
|
"extensions:marketplace-search",
|
|
async (
|
|
_event,
|
|
params: {
|
|
query?: string;
|
|
tags?: string[];
|
|
sort?: "popular" | "recent" | "rating";
|
|
page?: number;
|
|
pageSize?: number;
|
|
},
|
|
) => {
|
|
try {
|
|
return await searchMarketplace(params);
|
|
} catch (error: unknown) {
|
|
return {
|
|
extensions: [],
|
|
total: 0,
|
|
page: 1,
|
|
pageSize: 20,
|
|
error: getErrorMessage(error),
|
|
};
|
|
}
|
|
},
|
|
);
|
|
|
|
// Get a specific marketplace extension
|
|
ipcMain.handle("extensions:marketplace-get", async (_event, id: string) => {
|
|
return getMarketplaceExtension(id);
|
|
});
|
|
|
|
// Download and install a marketplace extension
|
|
ipcMain.handle(
|
|
"extensions:marketplace-install",
|
|
async (_event, extensionId: string, downloadUrl: string) => {
|
|
return downloadAndInstallExtension(extensionId, downloadUrl);
|
|
},
|
|
);
|
|
|
|
// Submit an extension for marketplace review
|
|
ipcMain.handle("extensions:marketplace-submit", async (_event, extensionId: string) => {
|
|
return submitExtensionForReview(extensionId);
|
|
});
|
|
|
|
// ── Admin Review System ─────────────────────────────────────────────
|
|
|
|
// Fetch pending reviews (admin only)
|
|
ipcMain.handle(
|
|
"extensions:reviews-list",
|
|
async (
|
|
_event,
|
|
params: {
|
|
status?: MarketplaceReviewStatus;
|
|
page?: number;
|
|
pageSize?: number;
|
|
},
|
|
) => {
|
|
try {
|
|
return await fetchPendingReviews(params);
|
|
} catch (error: unknown) {
|
|
return { reviews: [], total: 0, error: getErrorMessage(error) };
|
|
}
|
|
},
|
|
);
|
|
|
|
// Update review status (admin only)
|
|
ipcMain.handle(
|
|
"extensions:review-update",
|
|
async (_event, reviewId: string, status: MarketplaceReviewStatus, notes?: string) => {
|
|
return updateReviewStatus(reviewId, status, notes);
|
|
},
|
|
);
|
|
}
|