/* ----------------------- * * Utility Types * * ----------------------- */ /** * Allows a value to be a single item or an array of items. Useful for handling cases where a function accepts multiple values. */ export type MaybeMultiple = T | Array; /** * Allows a value to be synchronous or asynchronous. * Used for functions that may return a Promise or a direct value. */ export type MaybeAsync = T | Promise; /** * Resolves the inner value of a Promise. */ export type ResolvedType = T extends Promise ? Value : T; /* ----------------------- * * Action System * * ----------------------- */ /** * Extendable interface for defining custom plugin actions. */ export interface GasketActions { } /** * Type representing the keys of registered Gasket actions. */ export type ActionId = keyof GasketActions; /** * Defines a handler for a specific action type. */ export type ActionHandler = ( gasket: Gasket, ...args: Parameters ) => ReturnType; /* ----------------------- * * Hook System Types * * ----------------------- */ /** * Built-in lifecycle hooks supported by Gasket. */ export interface HookExecTypes { /** Runs during initialization. */ init(): void; /** Runs during configuration and can modify the config. */ configure(config: GasketConfig): GasketConfig; /** Runs once the application is ready. */ ready(): MaybeAsync; /** Runs to prepare the application. */ prepare(config: GasketConfig): MaybeAsync; } /** * Available hook names. */ export type HookId = keyof HookExecTypes; /** * Defines execution order for hooks. */ export type HookTimings = { /** Run this hook first. */ first?: boolean; /** Run this hook last. */ last?: boolean; /** Run this hook before these plugin names. */ before?: string[]; /** Run this hook after these plugin names. */ after?: string[]; }; /** * Function signature for hook handler methods. */ export type HookHandler = ( gasket: Gasket, ...args: Parameters ) => MaybeAsync>; /** * Function signature for applying hooks. */ export type ApplyHookHandler = ( ...args: Parameters ) => ReturnType; /** * Hook wrapped with timing configuration. */ type HookWithTimings = { timing: HookTimings; handler: HookHandler; }; /** * Method signature for invoking a hook. */ export type HookInvoke = ( gasket: Gasket, ...args: Parameters ) => ReturnType; /** * Hook subscriber entry used internally to track invocation. */ export type HookSubscriber = { ordering: HookTimings; invoke: HookInvoke; }; /** * Configuration structure for all hook subscribers. */ export type HookConfig = { subscribers: Record; }; /** * A valid hook can either be a simple handler or a hook with timing metadata. */ export type Hook = HookWithTimings | HookHandler; /* ----------------------- * * Plugin Definition * * ----------------------- */ type PluginBase = { /** Plugin name (required) */ name: string; /** Optional version number */ version?: string; /** Optional description */ description?: string; /** Optional dependency plugin names */ dependencies?: Array; /** Arbitrary plugin-specific metadata */ metadata?: Record; }; type PluginHooks = { [K in HookId]?: Hook }; type PluginActions = { [K in ActionId]?: ActionHandler }; /** * A Gasket plugin defines hooks and/or actions, plus plugin metadata. * At least one of `hooks` or `actions` must be provided. */ export type Plugin = PluginBase & ( | { hooks: PluginHooks; actions?: PluginActions } | { hooks?: PluginHooks; actions: PluginActions } ); /** * Preset is a plugin without any actions defined. */ export type Preset = Omit; /** * Function signature to iterate over plugin names. */ export type PluginIterator = (plugin: string) => void; /** * A thunk used for executing a plugin's async hook implementation. */ export type PluginThunk = ( gasket: Gasket, pluginTasks: Record>, ...args: Parameters ) => Promise>; /** * A sync version of PluginThunk. */ export type SyncPluginThunk = ( gasket: Gasket, ...args: any[] ) => any; type RemainingArgs any> = Parameters extends [any, any, ...infer R] ? R : []; /** * Thunk type for waterfall-style hooks that pass a value between plugins. */ export type WaterfallThunk = ( gasket: Gasket, value: Parameters[1], ...args: RemainingArgs ) => Promise>; /* ----------------------------- * * Gasket Engine Definition * * ----------------------------- */ /** * Core engine that manages plugin hooks and execution. */ export interface GasketEngine { /** Available plugin actions */ actions: GasketActions; /** * Register new plugins onto the Gasket engine. */ registerPlugins(plugins: Plugin[]): void; /** Execute a hook asynchronously */ exec(gasket: Gasket, hook: string, ...args: any[]): Promise; /** Execute a hook synchronously */ execSync(gasket: Gasket, hook: string, ...args: any[]): any[]; /** Execute a waterfall hook asynchronously */ execWaterfall(gasket: Gasket, hook: string, value: any, ...args: any[]): Promise; /** Execute a waterfall hook synchronously */ execWaterfallSync(gasket: Gasket, hook: string, value: any, ...args: any[]): any; /** Execute a hook and return results keyed by plugin */ execMap(gasket: Gasket, hook: string, ...args: any[]): Promise>; /** Execute a hook and return results synchronously, keyed by plugin */ execMapSync(gasket: Gasket, hook: string, ...args: any[]): Record; /** Apply a function to each hook handler */ execApply( gasket: Gasket, hook: string, callback: (plugin: Plugin, handler: (...args: any[]) => any) => Promise ): Promise; /** Sync version of execApply */ execApplySync( gasket: Gasket, hook: string, callback: (plugin: Plugin, handler: (...args: any[]) => any) => Return ): Return[]; /** * Register a hook handler manually. */ hook(opts: { event: Id; pluginName?: string; timing?: HookTimings; handler: HookHandler; }): void; } /** * Available execution strategies for hook lifecycles. */ export type ExecutionType = | 'exec' | 'execMap' | 'execSync' | 'execApply' | 'execMapSync' | 'execApplySync' | 'execWaterfall' | 'execWaterfallSync'; /** * Map of lifecycle event names to their execution plans. */ export type PlansByEvent = Record>>; /* ----------------------------- * * Gasket Engine Utilities * * ----------------------------- */ /** * Create a new GasketEngine instance from plugins. */ export function GasketEngine_Constructor(plugins: Plugin[]): GasketEngine; /** * Register new plugins onto the Gasket engine. */ export function GasketEngine_RegisterPlugins(plugins: Plugin[]): void; /** * Create and run a cached hook execution plan. */ export function GasketEngine_ExecWithCachedPlan(options: { event: string; type: string; prepare: (hookConfig: HookConfig) => Plan; exec: (plan: Plan) => Result; }): Result; /** * Register a new hook dynamically at runtime. */ export function GasketEngine_Hook(options: { event: Id; pluginName?: string; timing?: HookTimings; handler: HookHandler; }): void; /** * Execute all hooks for a given event. */ export function GasketEngine_Exec( gasket: Gasket, event: string, ...args: any[] ): Promise; /** * Synchronous version of exec. */ export function GasketEngine_ExecSync( gasket: Gasket, event: string, ...args: any[] ): any[]; /** * Arguments tuple for a given hook event. */ export type HookArgs = Parameters; /** * Execute a hook and return results per plugin. */ export function GasketEngine_ExecMap( gasket: Gasket, event: Id, ...args: Parameters ): Promise>>>; /** * Synchronous version of execMap. */ export function GasketEngine_ExecMapSync( gasket: Gasket, event: string, ...args: any[] ): Record; /** * Execute a waterfall hook chain. */ export function GasketEngine_ExecWaterfall( gasket: Gasket, event: Id, initial: Parameters[1], ...args: RemainingArgs ): Promise>; /** * Synchronous version of execWaterfall. */ export function GasketEngine_ExecWaterfallSync( gasket: Gasket, event: string, initial: any, ...args: any[] ): any; /** * Apply a function to each plugin hook. */ export function GasketEngine_ExecApply( gasket: Gasket, event: string, applyFn: (plugin: Plugin, handler: (...args: any[]) => any) => any ): Promise; /** * Synchronous version of execApply. */ export function GasketEngine_ExecApplySync( gasket: Gasket, event: string, applyFn: (plugin: Plugin, handler: (...args: any[]) => any) => any ): any[]; /* ----------------------------- * * Gasket Configuration * * ----------------------------- */ /** * Resolved runtime Gasket configuration. */ export interface GasketConfig { plugins: Plugin[]; root: string; env: string; command?: string; } /** * Pre-normalized Gasket config, allows ESM plugins. */ export type PreNormalizedGasketConfig = Omit & { plugins: (Plugin | { default: Plugin })[]; }; /** * Configuration overrides for specific environments or commands. */ export type GasketConfigDefinition = Omit & { root?: string; env?: string; environments?: Record; commands?: Record; }; type PartialRecursive = T extends object ? { [K in keyof T]?: PartialRecursive } | undefined : T | undefined; type ConfigKeysRequiringFullEnvConfig = 'plugins'; type GasketConfigOverrides = & PartialRecursive> & Partial>; /* ----------------------------- * * Gasket Core * * ----------------------------- */ /** * Main Gasket instance used throughout apps and plugins. */ export interface Gasket { /** Final config after merging env overrides */ config: GasketConfig; /** Internal engine for lifecycle hook execution */ engine: GasketEngine; /** Used for registering hooks */ hook: GasketEngine['hook']; /** Unique symbol for this instance */ symbol: symbol; /** Resolves when app is fully ready */ isReady: Promise; /** Access plugin actions */ readonly actions: GasketEngine['actions']; /** Trace subtree for this Gasket instance */ traceBranch(): GasketTrace; /** Returns the root Gasket instance */ traceRoot(): Gasket; /** Optional debug hook trace helper */ traceHookStart?: (pluginName: string, event: string) => void; /** Execute a lifecycle event asynchronously */ exec(event: string, ...args: any[]): Promise; /** Execute a lifecycle event synchronously */ execSync(event: string, ...args: any[]): any[]; /** Execute a lifecycle event and return final result from waterfall (async) */ execWaterfall(event: string, input: any, ...args: any[]): Promise; /** Execute a lifecycle event and return final result from waterfall (sync) */ execWaterfallSync(event: string, input: any, ...args: any[]): any; [key: string]: any; } export interface Tracer { /** Stack of trace entries for the current branch */ traceStack: string[]; /** Generic trace function used internally */ trace: (message: string) => void; /** Marks the start of a plugin's lifecycle hook */ traceHookStart(pluginName: string, event: string): void; /** Marks the start of a lifecycle execution */ traceLifecycleStart(type: string, event: string): void; /** Marks the end of a lifecycle execution (currently stubbed) */ traceLifecycleEnd(type: string, event: string): void; /** Marks the start of a traced action */ traceActionStart(name: string): void; /** Marks the end of a traced action (currently stubbed) */ traceActionEnd(name: string): void; } /** * Gasket instance with debugging trace helper. */ export interface GasketTrace { /** Unique branch ID */ branchId: number; /** Reference to the lifecycle engine */ engine: GasketEngine; /** Trace output function */ trace: (msg: string) => void; /** Lifecycle hook start tracer */ traceHookStart: (pluginName: string, event: string) => void; /** Returns the root Gasket instance */ traceRoot(): Gasket; /** Returns a new GasketTrace proxy branch */ traceBranch(): GasketTrace; /** Internal tracer helper */ _tracer: Tracer /** Proxy that combines both Gasket and GasketTrace behavior */ _proxy: Gasket & GasketTrace; } export interface GasketTraceConstructor { new(parent: Gasket | GasketTrace, newBranchId?: number): GasketTrace; } /* ----------------------------- * * Legacy / Compatibility * * ----------------------------- */ /** * Legacy interface for request-like shape. * @deprecated - Use class from `@gasket/request` instead. */ export interface GasketRequest { cookies: Record; headers: Record; query?: Record; } /* ----------------------------- * * Factory Function * * ----------------------------- */ /** * Factory to create a new Gasket instance with provided config. */ export function makeGasket(config: GasketConfigDefinition): Gasket; export type isolateLifecycle = ( source: Gasket | GasketTrace, name: string, fn: HookHandler ) => HookHandler; export type isolateAction = (source: GasketTrace, name: string, fn: ActionHandler) => ActionHandler export type interceptActions = (source: GasketTrace, actions: GasketActions) => GasketActions export type makeTraceBranch = (gasket: Gasket | GasketTrace) => GasketTrace /* ----------------------- * * Engine Utils Types * * ----------------------- */ /** * Lifecycle method names available on the engine. * Used for dynamically binding context for destructured methods. */ export const lifecycleMethods: string[]; /** * Normalize hook to ensure it is in the { handler, timing } shape * @template {HookId} Id * @param {Hook} hook - The hook to normalize * @returns {object} Normalized hook with handler and optional timing */ export function normalizeHook( hook: Hook ): { handler: HookHandler; timing?: HookTimings }; /** * Create a thunk for async plugin execution * @template {HookId} Id * @param {string} plugin - Name of the plugin * @param {HookSubscriber} subscriber - Hook subscriber configuration * @param {string} event - Name of the event * @param {Function} [traceHookStart] - Optional function to trace hook start * @returns {PluginThunk} Async thunk function for plugin execution */ export function createAsyncThunk( plugin: string, subscriber: HookSubscriber, event: string, traceHookStart?: (pluginName: string, event: string) => void ): PluginThunk; /** * Create a thunk for sync plugin execution * @param {string} plugin - Name of the plugin * @param {HookSubscriber} subscriber - Hook subscriber configuration * @param {string} event - Name of the event * @param {Function} [traceHookStart] - Optional function to trace hook start * @returns {SyncPluginThunk} Sync thunk function for plugin execution */ export function createSyncThunk( plugin: string, subscriber: HookSubscriber, event: string, traceHookStart?: (pluginName: string, event: string) => void ): SyncPluginThunk; /** * Generate a unique plugin name for dynamically registered hooks. * Used when no `pluginName` is provided explicitly. * @returns {string} Unique plugin name string */ export function getDynamicPluginName(): string;