Files
factorio-clusterio/packages/lib/src/plugin.ts
T
bbassieandClaude Opus 5.5 f40113e01c Rename PluginWebpackEnvInfo to PluginWebEnvInfo
The old name is kept as a deprecated alias.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 22:53:13 +00:00

156 lines
4.3 KiB
TypeScript

/**
* Plugin interfaces and utilities.
* @module lib/plugin
*/
import type { Static } from "@sinclair/typebox";
import type { Logger } from "./logging.js";
import type { ConfigSchema, FieldDefinition } from "./config/index.js";
import type { PermissionDefinition } from "./permissions.js";
import type { PlayerStats, Role } from "./data/index.js";
import type { SyncHook } from "./SyncHook.js";
import type { ErrorClass } from "./link/index.js";
export const PluginFeatureFlags = [
/** The plugin requires module code to be patched into the save */
"SavePatching",
/** The plugin requires access to script commands over rcon */
"ScriptCommands",
/** The plugin requires UDP messaging with the Factorio server */
"LuaUdp",
] as const;
/** Used to define the plugin export in plugins */
export type PluginDeclaration = {
name: string;
title: string;
description?: string;
controllerEntrypoint?: string;
controllerConfigFields?: Record<string, FieldDefinition>;
hostEntrypoint?: string;
hostConfigFields?: Record<string, FieldDefinition>;
instanceEntrypoint?: string;
instanceConfigFields?: Record<string, FieldDefinition>;
ctlEntrypoint?: string;
webEntrypoint?: string;
ctlConfigFields?: Record<string, FieldDefinition>;
migrationEntrypoint?: string;
features?: (typeof PluginFeatureFlags)[number][];
messages?: any[];
errors?: ErrorClass[];
permissions?: PermissionDefinition[];
routes?: string[];
};
/**
* Check if a plugin is expected to ship a web build.
*
* Mirrors the rule used by the create tool: a web build is generated when the
* plugin has a web or controller entrypoint or defines config fields.
*/
export function pluginNeedsWebBuild(info: PluginDeclaration) {
return Boolean(
info.webEntrypoint
|| info.controllerEntrypoint
|| info.controllerConfigFields
|| info.hostConfigFields
|| info.instanceConfigFields
|| info.ctlConfigFields
);
}
export type PluginNodeEnvInfo = PluginDeclaration & {
/**
* Path to the folder with the static files that should be hosted on the web
* server in order for the web interface to be able to load the plugin.
*/
webStaticPath: string;
/**
* Absolute path to the package.json file for the plugin.
*/
packagePath: string;
requirePath: string;
version: string;
manifest: any;
/**
* NPM package this plugin is published as. Not present if the package
* is private or the path used to load it does not match the name of the
* package.
*/
npmPackage?: string;
/**
* Directory of an npm package providing a plugin with the same name
* that was skipped on startup as this plugin was already in the list.
*/
skippedNpmPackage?: string;
};
export type PluginWebEnvInfo = PluginDeclaration & {
container?: any;
package?: any;
enabled?: boolean;
error?: string;
};
/** @deprecated Use PluginWebEnvInfo */
export type PluginWebpackEnvInfo = PluginWebEnvInfo;
/**
* Information about the event.
*/
export interface PlayerEvent {
type: "join" | "leave" | "import" | "promote" | "demote" | "ban" | "unban" | "whitelisted" | "unwhitelisted";
/** Name of the player that caused the event */
name: string,
/**
* Only present for type "leave" and "ban". Reason for player leaving the
* game, one of the possible reasons in defines.disconnect_reason
* or "server_quit" if the server exits while the player is online.
* When type is "ban" this is the reason given for the ban.
*/
reason?: string;
/**
* Statistics recorded for this player on the instance this event
* originated from.
*/
stats: PlayerStats,
}
export type PluginLoadContext<
Context extends object,
Info extends PluginDeclaration = PluginNodeEnvInfo
> = Context & {
logger: Logger;
plugin: Info;
};
/** Hooks for migrating data that Clusterio stores on behalf of plugins */
export type MigrationHooks = {
controllerConfig: SyncHook<ConfigSchema>;
hostConfig: SyncHook<ConfigSchema>;
instanceConfig: SyncHook<ConfigSchema>;
role: SyncHook<Static<typeof Role.jsonSchema>>;
};
export type MigrationContext = PluginLoadContext<{ hooks: MigrationHooks }>;
export type PluginClass<
Context extends object,
Info extends PluginDeclaration,
> = {
new (...args: any[]): any;
fromContext(context: PluginLoadContext<Context, Info>): {
init(): Promise<void>;
detachHooks(): void;
};
};
export type PluginType =
Extract<keyof PluginDeclaration, `${string}Entrypoint`> extends `${infer P}Entrypoint` ? P : never;