/** * Declares Plugin manifests, lifecycle contexts, setup access, capabilities, operations, tools, and definitions. * * @module */ import type { CapabilityRequirementIdentity, CapabilityToken } from './capability-token.js'; import type { CommittedEventListener, PluginEventMap } from './committed-event-bus.js'; import type { Disposable, MaybePromise } from './disposable.js'; import type { OperationDefinition, OperationExecutionContext, OperationRunOptions, OperationToken } from './operation-registry.js'; import type { PluginIdentity, PluginRef } from './plugin-ref.js'; import type { ScopedPluginStateStore } from './plugin-state-store.js'; import type { ToolDefinition, ToolExitReason, ToolStatus, ToolStatusListener, ToolStatusSubscriptionOptions } from './tool-coordinator.js'; /** Privileged integration boundaries that a Plugin can declare in its manifest. */ export type PluginPermission = 'fabric:objects' | 'fabric:canvas-read' | 'fabric:custom-class' | 'fabric:global-mutation' | 'core:raster-mutation' | 'core:geometry-participant' | 'core:export-contributor'; /** Immutable metadata validated before Plugin setup starts. */ export interface PluginManifest { readonly id: string; readonly version: string; readonly apiVersion: string; readonly engine: string; readonly requiresPlugins?: readonly PluginRef[]; readonly requires?: readonly CapabilityRequirementIdentity[]; readonly optional?: readonly CapabilityRequirementIdentity[]; readonly permissions?: readonly PluginPermission[]; } /** Declares one typed Capability implementation and its runtime version. */ export interface CapabilityProviderDefinition { readonly token: CapabilityToken; readonly implementation: TPort; readonly version: string; } /** Runtime version declaration supplied when a Plugin provides a Capability. */ export interface CapabilityProviderOptions { readonly version: string; readonly requiredPermission?: PluginPermission; } /** Shared shape for Plugin APIs that own atomic runtime configuration. */ export interface ConfigurablePluginApi { configure(patch: Partial): void | Promise; getConfiguration(): Readonly; } /** Public cleanup ownership available only during Plugin setup. */ export interface DisposableScope { readonly active: boolean; add(disposable: TDisposable): TDisposable; } /** Availability of one Capability declared through a Plugin manifest's optional list. */ export type OptionalCapabilityStatus = 'available' | 'missing' | 'incompatible'; export interface PluginCapabilityReader { require(token: CapabilityToken): TPort; optional(token: CapabilityToken): TPort | null; getOptionalStatus(token: CapabilityToken): OptionalCapabilityStatus; } export interface PluginCapabilitySetupAccess extends PluginCapabilityReader { provide(token: CapabilityToken, implementation: TPort, options: CapabilityProviderOptions): Disposable; } export interface PluginOperationAccess { begin(operationId: string): OperationToken; run(operationId: string, args: TArgs, task: (args: TArgs, context: OperationExecutionContext) => MaybePromise, options?: OperationRunOptions): Promise; get(operationId: string): OperationDefinition | null; isActive(operationId?: string): boolean; } export interface PluginOperationSetupAccess extends PluginOperationAccess { register(definition: OperationDefinition): Disposable; } export interface PluginToolAccess { enter(toolId: string): Promise; exit(reason?: ToolExitReason): Promise; getActiveToolId(): string | null; canRunOperation(operationId: string): boolean; subscribe(listener: PluginToolStatusListener, options?: PluginToolStatusSubscriptionOptions): Disposable; } export type PluginToolStatus = ToolStatus; export type PluginToolStatusListener = ToolStatusListener; export type PluginToolStatusSubscriptionOptions = Readonly; export interface PluginToolSetupAccess extends PluginToolAccess { register(definition: ToolDefinition): Disposable; } export interface PluginCommittedEventAccess { emitCommitted(eventName: TKey, payload: TEvents[TKey]): Promise; } export interface PluginCommittedEventSetupAccess extends PluginCommittedEventAccess { on(eventName: TKey, listener: CommittedEventListener): Disposable; } export interface PluginLifecycleContext { readonly plugin: PluginIdentity; readonly pluginId: string; readonly state: ScopedPluginStateStore; readonly capabilities: PluginCapabilityReader; readonly operations: PluginOperationAccess; readonly tools: PluginToolAccess; readonly events: PluginCommittedEventAccess; } /** Lifecycle context for image notifications that can be cancelled by the host operation. */ export interface PluginImageLifecycleContext extends PluginLifecycleContext { readonly signal: AbortSignal; } export interface PluginSetupContext { readonly plugin: PluginIdentity; readonly pluginId: string; readonly state: ScopedPluginStateStore; readonly capabilities: PluginCapabilitySetupAccess; readonly operations: PluginOperationSetupAccess; readonly tools: PluginToolSetupAccess; readonly events: PluginCommittedEventSetupAccess; readonly disposables: DisposableScope; } export interface EditorPluginDefinition { readonly ref: PluginIdentity; readonly manifest: PluginManifest; setup(context: PluginSetupContext): MaybePromise; onInit?(context: PluginLifecycleContext): MaybePromise; onImageLoaded?(image: unknown, context: PluginImageLifecycleContext): MaybePromise; onImageCleared?(context: PluginImageLifecycleContext): MaybePromise; onDispose?(context: PluginLifecycleContext): MaybePromise; } export interface EditorPlugin extends EditorPluginDefinition { readonly ref: PluginRef; setup(context: PluginSetupContext): MaybePromise; } /** A plugin whose setup/init/dispose hooks are safe for synchronous installation. */ export interface SynchronousEditorPlugin extends EditorPlugin { readonly setupMode: 'sync'; setup(context: PluginSetupContext): TApi; onInit?(context: PluginLifecycleContext): void; onDispose?(context: PluginLifecycleContext): void; }