/** * Feature Service Types * * Type definitions for the Ductape Features code-first API. */ import { IProductFeature, IProductFeatureStep, IFeatureOptions, IFeatureSignal, IFeatureQuery, IFeatureEnv, IFeatureStepOptions, IFeatureStepRollback, FeatureStepType, FeatureRollbackStrategy, FeatureStatus, IActionRequest, INotificationRequest, IDbActionRequest, IStorageRequest } from '../../types'; import type { IPortableFunctionContract, PortableFunctionClient } from '../../functions'; /** * Configuration options for FeatureService initialization */ export interface IFeatureServiceConfig { /** Workspace ID */ workspace_id: string; /** Public key for authentication */ public_key: string; /** User ID */ user_id: string; /** Authentication token */ token: string; /** Environment type (staging, production, local) */ env_type: string; /** Optional Redis client for caching */ redis_client?: any; } /** * Feature configuration for local registration */ export interface IFeatureConfig { /** Human-readable name */ name: string; /** Unique feature tag */ tag: string; /** Description */ description?: string; /** Input schema */ input?: Record; /** Output schema */ output?: Record; /** Feature steps */ steps: IProductFeatureStep[]; /** Signal definitions */ signals?: Record; /** Query definitions */ queries?: Record; /** Feature options */ options?: IFeatureOptions; /** Environment configurations */ envs?: IFeatureEnv[]; } /** * Additional context metadata for feature execution */ export interface IFeatureContextMeta { /** Request ID */ request_id?: string; /** Correlation ID */ correlation_id?: string; /** Parent feature ID (for child features) */ parent_feature_id?: string; /** Parent step tag (for child features) */ parent_step_tag?: string; /** Custom metadata */ [key: string]: unknown; } /** * Logger interface for feature execution */ export interface IFeatureLogger { debug(message: string, data?: Record): void; info(message: string, data?: Record): void; warn(message: string, data?: Record): void; error(message: string, data?: Record): void; } /** * Wait options for signals */ export interface IWaitOptions { /** Timeout duration (ms or duration string like '1h', '30m') */ timeout?: number | string; } /** * Child feature options */ export interface IChildFeatureOptions { /** Timeout for child feature */ timeout?: number | string; /** Number of retries */ retries?: number; /** How to handle parent cancellation */ parent_close_policy?: 'terminate' | 'abandon' | 'request_cancel'; /** Idempotency key */ idempotency_key?: string; } /** * Rollback result */ export interface IRollbackResult { /** Whether rollback was successful */ success: boolean; /** Steps that were rolled back */ rolled_back_steps: string[]; /** Steps that failed to rollback */ failed_steps?: Array<{ tag: string; error: string; }>; /** Reason for triggering rollback */ reason: string; } /** * Action context for feature steps */ export interface IFeatureActionContext { run(options: { app: string; action: string; input: IActionRequest; retries?: number; timeout?: number; }): Promise; } /** * Database context for feature steps */ export interface IFeatureDatabaseContext { execute(options: { database: string; action: string; input: IDbActionRequest; retries?: number; timeout?: number; }): Promise; query(options: { database: string; table: string; select?: string[]; where?: Record; orderBy?: { column: string; order: 'ASC' | 'DESC'; } | Array<{ column: string; order: 'ASC' | 'DESC'; }>; limit?: number; offset?: number; }): Promise; insert(options: { database: string; table: string; data: Record; }): Promise; update(options: { database: string; table: string; data: Record; where: Record; }): Promise; delete(options: { database: string; table: string; where: Record; }): Promise; } /** * Graph context for feature steps */ export interface IFeatureGraphContext { execute(options: { graph: string; action: string; input: Record; }): Promise; createNode(options: { graph: string; labels: string[]; properties: Record; }): Promise; updateNode(options: { graph: string; id: string | number; properties: Record; }): Promise; deleteNode(options: { graph: string; id: string | number; }): Promise; createRelationship(options: { graph: string; from: string; to: string; type: string; properties?: Record; }): Promise; deleteRelationship(options: { graph: string; id: string | number; }): Promise; query(options: { graph: string; action: string; params?: Record; }): Promise; } /** Vector database context for serializable Feature steps. */ export interface IFeatureVectorContext { query(options: { vector: string; values: number[]; topK: number; namespace?: string; filter?: Record; includeValues?: boolean; includeMetadata?: boolean; minScore?: number; }): Promise; upsert(options: { vector: string; vectors: Array<{ id: string; values: number[]; metadata?: Record; sparseValues?: { indices: number[]; values: number[]; }; }>; namespace?: string; wait?: boolean; }): Promise; upsertOne(options: { vector: string; id: string; values: number[]; metadata?: Record; namespace?: string; }): Promise; deleteVectors(options: { vector: string; ids?: string[]; namespace?: string; deleteAll?: boolean; filter?: Record; }): Promise; execute(options: { vector: string; action: string; input: Record; }): Promise; } /** Session lifecycle context for serializable Feature steps. */ export interface IFeatureSessionsContext { start(options: { session: string; data: Record; cache?: string; }): Promise; verify(options: { session: string; token: string; cache?: string; }): Promise; refresh(options: { session: string; refreshToken: string; cache?: string; }): Promise; revoke(options: { session: string; sessionId?: string; identifier?: string; }): Promise; list(options: { session: string; identifier?: string; page?: number; limit?: number; cache?: string; }): Promise; } /** * Notification context for feature steps */ export interface IFeatureNotificationContext { send(options: { notification: string; event: string; input: INotificationRequest; retries?: number; }): Promise; email(options: { notification: string; event: string; recipients: string[]; subject: Record; template: Record; }): Promise; push(options: { notification: string; event: string; tokens: string[]; title: Record; body: Record; data?: Record; }): Promise; sms(options: { notification: string; event: string; phones: string[]; message: Record; }): Promise; } /** * Storage context for feature steps */ export interface IFeatureStorageContext { upload(options: { storage: string; event: string; input: IStorageRequest; retries?: number; }): Promise; download(options: { storage: string; event: string; input: IStorageRequest; }): Promise; delete(options: { storage: string; event: string; input: { file_key: string; }; }): Promise; } /** * Messaging context for feature steps (Ductape primitive). * Use ctx.events.produce() to publish to a message broker. */ export interface IFeatureMessagingContext { /** * Publish a message to a broker topic. * @param options.event - Full event string "broker-tag:topic-tag" (e.g. "order-events:payment-processed") * @param options.message - Message payload */ produce(options: { event: string; message: Record; }): Promise; } /** * Publish context for feature steps. * @deprecated Prefer ctx.events.produce() (Ductape primitive). */ export interface IFeaturePublishContext { send(options: { broker: string; event: string; input: { message: Record; }; retries?: number; }): Promise; } /** * Quota context for feature steps */ export interface IFeatureQuotaContext { execute(options: { quota: string; input: Record; timeout?: number; }): Promise; } /** * Fallback context for feature steps */ export interface IFeatureFallbackContext { execute(options: { fallback: string; input: Record; timeout?: number; }): Promise; } /** * Healthcheck context for feature steps */ export interface IFeatureHealthcheckContext { getStatus(tag: string): Promise<{ status: 'available' | 'unavailable'; lastChecked?: string; lastLatency?: number; }>; } export interface IFeatureFunctionsContext { /** Obtain a typed recording proxy. Calls compile to portable function steps. */ use(contract: T): PortableFunctionClient; /** Invoke a contract operation without creating a client variable. */ invoke(contract: IPortableFunctionContract, operation: string, input: Record): Promise; } /** * Transform context for data transformations */ export interface ITransformContext { /** Get the number of keys in an object */ size(obj: Record): number; /** Get the length of an array or string */ length(arr: unknown[] | string): number; /** Parse JSON string */ parseJson(str: string): T; /** Stringify to JSON */ stringify(obj: unknown): string; /** Convert to uppercase */ upper(str: string): string; /** Convert to lowercase */ lower(str: string): string; /** Trim whitespace */ trim(str: string): string; /** Split string */ split(str: string, separator: string): string[]; /** Join array */ join(arr: string[], separator: string): string; /** Get current timestamp */ now(): number; /** Format date */ formatDate(date: Date | number | string, format: string): string; } /** * File upload result */ export interface IFileUploadResult { file_key: string; url?: string; size?: number; content_type?: string; } /** * File download result */ export interface IFileDownloadResult { content: Buffer | string; content_type?: string; size?: number; } /** * Full feature context interface */ export interface IFeatureContext> { /** Feature input (read-only) */ readonly input: TInput; /** * Compile-time sample data supplied through recordInput/recordScenarios. * Use only to discover loops and branches while compiling. Values read from * this property are never serialized as runtime feature input references. */ readonly sampleInput: TInput; /** Feature metadata */ readonly feature_id: string; readonly feature_tag: string; readonly env: string; readonly product: string; readonly context: IFeatureContextMeta; /** Execution state */ readonly state: Record; readonly steps: Record; readonly completed_steps: string[]; readonly current_step: string | null; /** Session token in format: session_tag:jwt_token */ readonly session?: string; /** Step execution */ step(tag: string, handler: () => Promise, rollback?: ((result: T) => Promise) | null, options?: IFeatureStepOptions): Promise; /** Ductape components */ action: IFeatureActionContext; /** Alias for action — preferred name for calling app actions */ api: IFeatureActionContext; database: IFeatureDatabaseContext; graph: IFeatureGraphContext; vector: IFeatureVectorContext; sessions: IFeatureSessionsContext; notification: IFeatureNotificationContext; storage: IFeatureStorageContext; /** Message broker (Ductape primitive). Prefer over publish. */ events: IFeatureMessagingContext; /** @deprecated Prefer ctx.events.produce() */ publish: IFeaturePublishContext; /** Resilience components */ quota: IFeatureQuotaContext; fallback: IFeatureFallbackContext; healthcheck: IFeatureHealthcheckContext; /** Portable application functions. */ functions: IFeatureFunctionsContext; /** Data transformations */ transform: ITransformContext; /** Data references */ variable(app: string, key: string): unknown; constant(app: string, key: string): unknown; token(key: string): string; auth: Record; default(value: T | undefined, fallback: T): T; /** Control flow */ sleep(duration: number | string): Promise; waitForSignal(signal: string | string[], options?: IWaitOptions): Promise; checkpoint(name: string, metadata?: Record): Promise; /** State management */ setState(key: string, value: unknown): void; getState(key: string): T | undefined; /** Logging */ log: IFeatureLogger; /** Child features */ feature(childId: string, tag: string, input: TChildInput, options?: IChildFeatureOptions): Promise; /** Rollback control */ triggerRollback(reason: string): Promise; } /** * Feature handler function type */ export type FeatureHandler, TOutput = unknown> = (ctx: IFeatureContext) => Promise; /** * Options for defining a feature with code-first API */ export interface IDefineFeatureOptions, TOutput = unknown> { /** Target product (optional if using builder pattern) */ product?: string; /** Unique feature tag */ tag: string; /** Human-readable name */ name: string; /** Description */ description?: string; /** Input schema (field names and types for documentation/validation), e.g. { orderId: { type: 'string', required: true } } */ input?: Record; /** Output schema (optional, for documentation) */ output?: Record; /** Signal definitions */ signals?: Record; }>; /** Query definitions */ queries?: Record) => unknown; }>; /** Feature options */ options?: IFeatureOptions; /** Environment configurations */ envs?: IFeatureEnv[]; /** * Optional step result overrides when recording the handler. * Use when the handler branches on a step result (e.g. if (!validation.valid) return ...). * Key = step tag, value = result to return to the handler so it continues and records later steps. * Example: { validate: { valid: true } } so the handler does not early-return and process-payment is recorded. * Steps recorded after an overridden step get a condition so they only run when that step's real output matches (e.g. $Step{validate}{valid} == true). */ branchOverrides?: Record; /** * Sample input used during recording so loops and control flow see real values. * Example: { items: [{ id: '1' }, { id: '2' }] } so that for (const item of ctx.sampleInput.items) runs twice and records steps process-1, process-2. * Use unique step tags per iteration (e.g. ctx.step(`process-${item.id}`, ...)). */ recordInput?: TInput; /** * For switch/alternate branches: run the handler once per scenario with that as recordInput. * Read ctx.sampleInput for compile-time branch selection. Each recorded step gets a runtime condition matching that scenario. * Example: recordScenarios: [ { type: 'a' }, { type: 'b' } ] records both branches; handle-a gets condition $Input{type} == 'a', handle-b gets $Input{type} == 'b'. */ recordScenarios?: Record[]; /** Feature handler function */ handler: FeatureHandler; } /** * Options for executing a feature */ export interface IExecuteFeatureOptions { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature tag */ tag: string; /** Feature input */ input: Record; /** Pre-resolved product ID (avoids duplicate initProduct when provided) */ product_id?: string; /** Session token in format: session_tag:jwt_token */ session?: string; /** Idempotency key */ idempotency_key?: string; /** Cache tag */ cache?: string; /** Number of retries */ retries?: number; /** Timeout in ms */ timeout?: number; } /** * Feature execution result */ export interface IFeatureExecutionResult { /** Execution status */ status: FeatureStatus; /** Feature ID */ feature_id: string; /** Output data */ output?: T; /** Error message if failed */ error?: string; /** Execution time in ms */ execution_time: number; /** Completed steps */ completed_steps: string[]; /** Per-step timing (tag, duration_ms, success) for reporting */ step_timings?: Array<{ tag: string; duration_ms: number; success: boolean; }>; /** Failed step (if any) */ failed_step?: string; /** Rollback info (if rolled back) */ rollback_info?: { triggered_by: string; reason: string; rolled_back_steps: string[]; failed_rollbacks?: Array<{ tag: string; error: string; }>; }; } /** * Schedule configuration for dispatched features */ export interface IFeatureSchedule { /** Start time (timestamp or ISO string) */ start_at?: number | string; /** Cron expression for recurring */ cron?: string; /** Interval in ms for recurring */ every?: number; /** Maximum number of executions */ limit?: number; /** End date for recurring */ endDate?: number | string; /** Timezone */ tz?: string; } /** * Options for dispatching a feature */ export interface IFeatureDispatchInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature tag */ feature: string; /** Feature input */ input: Record; /** Schedule configuration */ schedule?: IFeatureSchedule; /** Session token in format: session_tag:jwt_token */ session?: string; /** Cache tag */ cache?: string; /** Number of retries */ retries?: number; } /** * Dispatch result */ export interface IFeatureDispatchResult { /** Job ID */ job_id: string; /** Job status */ status: 'scheduled' | 'queued' | 'running'; /** Scheduled timestamp */ scheduled_at?: number; /** Whether this is a recurring job */ recurring?: boolean; /** Next run timestamp (for recurring) */ next_run_at?: number; } /** * Options for sending a signal to a feature */ export interface ISendSignalOptions { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID */ feature_id: string; /** Signal name */ signal: string; /** Signal payload */ payload?: Record; } /** * Options for querying a feature */ export interface IQueryFeatureOptions { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID */ feature_id: string; /** Query name */ query: string; /** Query parameters */ params?: Record; } /** * Step builder interface for fluent API */ export interface IStepBuilder { /** Set as action step */ action(app: string, event: string): IStepBuilder; /** Set as database step */ database(database: string, event: string): IStepBuilder; /** Set as graph step */ graph(graph: string, action: string): IStepBuilder; /** Set as notification step */ notification(notification: string, event: string): IStepBuilder; /** Set as storage step */ storage(storage: string, event: string): IStepBuilder; /** Set as message broker produce step */ produce(broker: string, event: string): IStepBuilder; /** @deprecated Use produce() */ publish(broker: string, event: string): IStepBuilder; /** Set as quota step */ quota(quota: string): IStepBuilder; /** Set as fallback step */ fallback(fallback: string): IStepBuilder; /** Set as child feature step */ feature(feature: string): IStepBuilder; /** Set as sleep step */ sleep(duration: number | string): IStepBuilder; /** Set as wait for signal step */ waitForSignal(signal: string, timeout?: number | string): IStepBuilder; /** Set as checkpoint step */ checkpoint(): IStepBuilder; /** Set step input */ input(input: Record): IStepBuilder; /** Set step dependencies */ dependsOn(steps: string[]): IStepBuilder; /** Set step condition */ condition(condition: string): IStepBuilder; /** Set step options */ options(options: IFeatureStepOptions): IStepBuilder; /** Mark as optional */ optional(): IStepBuilder; /** Mark as critical */ critical(): IStepBuilder; /** Mark as allow_fail */ allowFail(): IStepBuilder; /** Set step name */ name(name: string): IStepBuilder; /** Configure rollback */ rollback(): IRollbackBuilder; /** Complete step definition and return to feature builder */ done(): IFeatureBuilder; } /** * Rollback builder interface for fluent API */ export interface IRollbackBuilder { /** Set as action rollback */ action(app: string, event: string): IRollbackBuilder; /** Set as database rollback */ database(database: string, event: string): IRollbackBuilder; /** Set as graph rollback */ graph(graph: string, action: string): IRollbackBuilder; /** Set as notification rollback */ notification(notification: string, event: string): IRollbackBuilder; /** Set as storage rollback */ storage(storage: string, event: string): IRollbackBuilder; /** Set as message broker produce rollback */ produce(broker: string, event: string): IRollbackBuilder; /** @deprecated Use produce() */ publish(broker: string, event: string): IRollbackBuilder; /** Set rollback input */ input(input: Record): IRollbackBuilder; /** Complete rollback definition and return to step builder */ done(): IStepBuilder; } /** * Feature builder interface for fluent API */ export interface IFeatureBuilder { /** Set feature name */ name(name: string): IFeatureBuilder; /** Set feature description */ description(description: string): IFeatureBuilder; /** Set input schema */ input(input: Record): IFeatureBuilder; /** Set output schema */ output(output: Record): IFeatureBuilder; /** Set feature options */ options(options: IFeatureOptions): IFeatureBuilder; /** Add environment */ env(slug: string, active?: boolean): IFeatureBuilder; /** Add signal */ signal(name: string, input?: Record): IFeatureBuilder; /** Add query */ query(name: string, handler?: string): IFeatureBuilder; /** Start defining a step */ step(tag: string): IStepBuilder; /** Build the feature schema */ build(): IProductFeature; /** Get compiled JSON schema */ toSchema(): IProductFeature; } /** * Options for replaying a feature */ export interface IFeatureReplayInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Original feature ID to replay */ feature_id: string; /** Override options for the replay */ options?: Partial; /** Reason for replay (for audit) */ reason?: string; /** Idempotency key */ idempotency_key?: string; } /** * Result of replaying a feature */ export interface IFeatureReplayResult extends IFeatureExecutionResult { /** Original feature ID that was replayed */ replayed_from: string; } /** * Options for restarting a feature */ export interface IFeatureRestartInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Original feature ID to restart */ feature_id: string; /** New input (replaces original) */ input?: Record; /** Partial input override (merged with original) */ input_override?: Record; /** Whether to merge input_override with original input */ merge_input?: boolean; /** Reason for restart (for audit) */ reason?: string; /** Override options */ options?: Partial; } /** * Result of restarting a feature */ export interface IFeatureRestartResult extends IFeatureExecutionResult { /** Original feature ID that was restarted */ restarted_from: string; } /** * Options for resuming a feature */ export interface IFeatureResumeInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID to resume */ feature_id: string; /** Resume from specific checkpoint */ from_checkpoint?: string; /** Resume from specific step */ from_step?: string; /** Steps to skip */ skip_steps?: string[]; /** Additional input for remaining steps */ input?: Record; } /** * Result of resuming a feature */ export interface IFeatureResumeResult extends IFeatureExecutionResult { /** Original feature ID that was resumed */ resumed_from: string; /** Checkpoint resumed from (if applicable) */ resumed_checkpoint?: string; } /** * Options for replaying from a specific step */ export interface IFeatureReplayFromStepInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Original feature ID */ feature_id: string; /** Step to start from */ from_step: string; /** Override outputs from previous steps */ step_outputs?: Record; /** Debug options */ debug?: { enabled: boolean; pause_after_step?: boolean; log_level?: 'info' | 'verbose' | 'debug'; }; } /** * Options for getting feature status */ export interface IFeatureStatusInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID */ feature_id: string; } /** * Feature status response */ export interface IFeatureStatus { /** Feature ID */ feature_id: string; /** Feature tag */ feature_tag: string; /** Current status */ status: FeatureStatus; /** Currently executing step */ current_step?: string; /** Completed step tags */ completed_steps: string[]; /** Feature state */ state: Record; /** Start timestamp */ started_at: number; /** Last update timestamp */ updated_at: number; /** Input data */ input?: Record; /** Output data (if completed) */ output?: unknown; /** Error (if failed) */ error?: { message: string; step?: string; code?: string; }; } /** * Options for cancelling a feature */ export interface IFeatureCancelInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID */ feature_id: string; /** Reason for cancellation */ reason?: string; } /** * Cancel result */ export interface IFeatureCancelResult { /** Whether cancellation was successful */ cancelled: boolean; /** Steps that were rolled back */ rolled_back_steps: string[]; /** Steps that failed to rollback */ failed_rollbacks?: Array<{ tag: string; error: string; }>; } /** * Options for getting feature history */ export interface IFeatureHistoryInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID */ feature_id: string; /** Include detailed step information */ include_step_details?: boolean; /** Include rollback details */ include_rollback_details?: boolean; } /** * Feature event types */ export type FeatureEventType = 'feature_started' | 'feature_completed' | 'feature_failed' | 'feature_cancelled' | 'feature_rolled_back' | 'step_started' | 'step_completed' | 'step_failed' | 'step_skipped' | 'step_rolled_back' | 'checkpoint_created' | 'signal_received' | 'signal_timeout' | 'rollback_started' | 'rollback_completed' | 'rollback_failed'; /** * Feature event */ export interface IFeatureEvent { /** Event type */ type: FeatureEventType; /** Timestamp */ timestamp: number; /** Event data */ data: Record; } /** * Checkpoint info */ export interface ICheckpoint { /** Checkpoint name */ name: string; /** Checkpoint metadata */ metadata?: Record; /** Timestamp */ timestamp: number; } /** * Feature history */ export interface IFeatureHistory { /** Feature ID */ feature_id: string; /** Feature tag */ feature_tag: string; /** Final status */ status: FeatureStatus; /** All events */ events: IFeatureEvent[]; /** Checkpoints */ checkpoints: ICheckpoint[]; /** Replay IDs (if this feature was replayed) */ replays?: string[]; /** Restart IDs (if this feature was restarted) */ restarts?: string[]; } /** * Options for getting step details */ export interface IStepDetailInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID */ feature_id: string; /** Step tag */ step_tag: string; } /** * Step status */ export type StepStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'rolled_back'; /** * Rollback status */ export type RollbackStatus = 'pending' | 'running' | 'completed' | 'failed' | 'skipped'; /** * Step error */ export interface IStepError { /** Error message */ message: string; /** Error code */ code?: string; /** Stack trace */ stack?: string; } /** * Step detail */ export interface IStepDetail { /** Step tag */ tag: string; /** Step name */ name?: string; /** Step status */ status: StepStatus; /** Step input */ input?: Record; /** Step output */ output?: Record; /** Step error (if failed) */ error?: IStepError; /** Number of attempts */ attempts: number; /** Start timestamp */ start_time?: number; /** End timestamp */ end_time?: number; /** Duration in ms */ duration?: number; /** Rollback status */ rollback_status?: RollbackStatus; /** Rollback error (if rollback failed) */ rollback_error?: string; } /** * Options for listing related executions */ export interface IRelatedExecutionsInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature ID */ feature_id: string; } /** * Related execution entry */ export interface IRelatedExecution { /** Feature ID */ feature_id: string; /** Execution type */ type: 'original' | 'replay' | 'restart' | 'resume'; /** Status */ status: FeatureStatus; /** Created timestamp */ created_at: number; /** Original feature ID (for replays) */ replayed_from?: string; /** Original feature ID (for restarts) */ restarted_from?: string; /** Original feature ID (for resumes) */ resumed_from?: string; } /** * Related executions response */ export interface IRelatedExecutions { /** Original feature ID */ original: string; /** All related executions */ executions: IRelatedExecution[]; } /** * Options for comparing executions */ export interface ICompareExecutionsInput { /** Product tag */ product: string; /** Environment slug */ env: string; /** Feature IDs to compare */ feature_ids: string[]; } /** * Step diff entry */ export interface IStepDiff { /** Step tag */ step: string; /** Status and output per feature */ [feature_id: string]: { status: StepStatus; output?: Record; error?: string; } | string; } /** * Execution comparison */ export interface IExecutionComparison { /** Feature IDs compared */ features: string[]; /** Input differences */ input_diff: Record; /** Step differences */ step_diffs: IStepDiff[]; /** Outcome differences */ outcome_diff: Record; } export { IProductFeature, IProductFeatureStep, IFeatureOptions, IFeatureSignal, IFeatureQuery, IFeatureEnv, IFeatureStepOptions, IFeatureStepRollback, FeatureStepType, FeatureRollbackStrategy, FeatureStatus, };