/** * Copyright (c) Meta Platforms, Inc. and affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @format */ export interface PluginDetails { name: string; specVersion: number; version: string; source: string; main: string; id: string; gatekeeper?: string; title: string; icon?: string; description?: string; category?: string; engines?: { [name: string]: string; }; bugs?: { email?: string; url?: string; }; flipperSDKVersion?: string; pluginType?: PluginType; supportedDevices?: SupportedDevice[]; supportedApps?: SupportedApp[]; publishedDocs?: { overview?: boolean; setup?: boolean; }; } export interface SupportedDevice { readonly os?: OS; readonly type?: DeviceType; readonly archived?: boolean; readonly specs?: DeviceSpec[]; } export interface SupportedApp { readonly appID?: string; readonly os?: OS; readonly type?: DeviceType; } export type OS = | 'iOS' | 'Android' | 'Metro' | 'Windows' | 'MacOS' | 'Browser' | 'Linux'; export type DeviceType = 'emulator' | 'physical' | 'dummy'; export type PluginType = 'client' | 'device'; export type DeviceSpec = 'KaiOS'; export interface ConcretePluginDetails extends PluginDetails { // Determines whether the plugin is a part of the Flipper JS bundle. isBundled: boolean; // Determines whether the plugin is physically available for activation in Flipper. isActivatable: boolean; } // Describes plugin which is a part of the Flipper JS bundle. export interface BundledPluginDetails extends ConcretePluginDetails { isBundled: true; isActivatable: true; } // Describes plugin installed on the disk. export interface InstalledPluginDetails extends ConcretePluginDetails { isBundled: false; isActivatable: true; dir: string; entry: string; } // Describes plugin physically available for activation in Flipper. export type ActivatablePluginDetails = | BundledPluginDetails | InstalledPluginDetails; // Describes plugin available for downloading. Until downloaded to the disk it is not available for activation in Flipper. export interface DownloadablePluginDetails extends ConcretePluginDetails { isActivatable: false; isBundled: false; downloadUrl: string; lastUpdated: Date; } export type UpdateResult = | {kind: 'not-installed'; version: string} | {kind: 'up-to-date'} | {kind: 'error'; error: Error} | {kind: 'update-available'; version: string}; export type UpdatablePlugin = { updateStatus: UpdateResult; }; export type UpdatablePluginDetails = InstalledPluginDetails & UpdatablePlugin; export function getPluginDetails(packageJson: any): PluginDetails { const specVersion = packageJson.$schema && packageJson.$schema === 'https://fbflipper.com/schemas/plugin-package/v2.json' ? 2 : 1; switch (specVersion) { case 1: return getPluginDetailsV1(packageJson); case 2: return getPluginDetailsV2(packageJson); default: throw new Error(`Unknown plugin format version: ${specVersion}`); } } // Plugins packaged using V1 are distributed as sources and compiled in run-time. function getPluginDetailsV1(packageJson: any): PluginDetails { return { specVersion: 1, name: packageJson.name, version: packageJson.version, main: 'dist/bundle.js', source: packageJson.main, id: packageJson.name, gatekeeper: packageJson.gatekeeper, icon: packageJson.icon, title: packageJson.title || packageJson.name, description: packageJson.description, category: packageJson.category, bugs: packageJson.bugs, flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'], pluginType: packageJson?.pluginType, supportedDevices: packageJson?.supportedDevices, supportedApps: packageJson?.supportedApps, engines: packageJson.engines, }; } // Plugins packaged using V2 are pre-bundled, so compilation in run-time is not required for them. function getPluginDetailsV2(packageJson: any): PluginDetails { return { specVersion: 2, name: packageJson.name, version: packageJson.version, main: packageJson.main, source: packageJson.flipperBundlerEntry, id: packageJson.id || packageJson.name, gatekeeper: packageJson.gatekeeper, icon: packageJson.icon, title: packageJson.title || packageJson.id || getTitleFromName(packageJson.name), description: packageJson.description, category: packageJson.category, bugs: packageJson.bugs, flipperSDKVersion: packageJson?.peerDependencies?.['flipper-plugin'], pluginType: packageJson?.pluginType, supportedDevices: packageJson?.supportedDevices, supportedApps: packageJson?.supportedApps, engines: packageJson.engines, publishedDocs: packageJson.publishedDocs, }; } function getTitleFromName(name: string): string { const prefix = 'flipper-plugin-'; if (name.startsWith(prefix)) { return name.substr(prefix.length); } return name; } export function isPluginJson(packageJson: any): boolean { return packageJson?.keywords?.includes('flipper-plugin'); }