import * as Effect from "effect/Effect"; import { createExecutorEffect, type CreateExecutorEffectOptions, type ExecutorEffect, } from "./executor-effect"; import type { ExecutorSdkPlugin, ExecutorSdkPluginExtensions, } from "./plugins"; type Promiseify = T extends Effect.Effect ? Promise : T extends (...args: infer Args) => infer Result ? (...args: Args) => Promiseify : T extends Promise ? Promise : T extends object ? { [Key in keyof T]: Promiseify } : T; export type Executor< TPlugins extends readonly ExecutorSdkPlugin[] = [], > = Omit< Promiseify>, "runtime" >; export type CreateExecutorOptions< TPlugins extends readonly ExecutorSdkPlugin[] = [], > = CreateExecutorEffectOptions & { plugins?: TPlugins; }; const toPromiseExecutor = < TPlugins extends readonly ExecutorSdkPlugin[], >( executor: ExecutorEffect & ExecutorSdkPluginExtensions, ): Executor => { const run = (effect: Effect.Effect) => Effect.runPromise(effect as Effect.Effect); const promiseifyValue = (value: unknown): unknown => { if (Effect.isEffect(value)) { return run(value); } if (value instanceof Promise) { return value; } if (typeof value === "function") { return (...args: Array) => promiseifyValue(value(...args)); } if (Array.isArray(value)) { return value.map(promiseifyValue); } if (value !== null && typeof value === "object") { return Object.fromEntries( Object.entries(value).map(([key, nestedValue]) => [ key, promiseifyValue(nestedValue), ]), ); } return value; }; const base = { scope: executor.scope, installation: executor.installation, scopeId: executor.scopeId, actorScopeId: executor.actorScopeId, resolutionScopeIds: executor.resolutionScopeIds, close: () => executor.close(), local: { installation: () => run(executor.local.installation()), config: () => run(executor.local.config()), }, secretStores: { list: () => run(executor.secretStores.list()), create: (payload: Parameters[0]) => run(executor.secretStores.create(payload)), update: (input: Parameters[0]) => run(executor.secretStores.update(input)), remove: (storeId: Parameters[0]) => run(executor.secretStores.remove(storeId)), }, secrets: { list: () => run(executor.secrets.list()), create: (payload: Parameters[0]) => run(executor.secrets.create(payload)), update: (input: Parameters[0]) => run(executor.secrets.update(input)), remove: (secretId: Parameters[0]) => run(executor.secrets.remove(secretId)), }, policies: { list: () => run(executor.policies.list()), create: (payload: Parameters[0]) => run(executor.policies.create(payload)), get: (policyId: Parameters[0]) => run(executor.policies.get(policyId)), update: ( policyId: Parameters[0], payload: Parameters[1], ) => run(executor.policies.update(policyId, payload)), remove: (policyId: Parameters[0]) => run(executor.policies.remove(policyId)), }, sources: { list: () => run(executor.sources.list()), get: (sourceId: Parameters[0]) => run(executor.sources.get(sourceId)), remove: (sourceId: Parameters[0]) => run(executor.sources.remove(sourceId)), inspection: { get: (sourceId: Parameters[0]) => run(executor.sources.inspection.get(sourceId)), tool: (input: Parameters[0]) => run(executor.sources.inspection.tool(input)), discover: ( input: Parameters[0], ) => run(executor.sources.inspection.discover(input)), }, }, executions: { list: () => run(executor.executions.list()), create: (payload: Parameters[0]) => run(executor.executions.create(payload)), get: (executionId: Parameters[0]) => run(executor.executions.get(executionId)), resume: ( executionId: Parameters[0], payload: Parameters[1], ) => run(executor.executions.resume(executionId, payload)), }, }; const coreKeys = new Set([ "runtime", "installation", "scope", "scopeId", "actorScopeId", "resolutionScopeIds", "close", "local", "secretStores", "secrets", "policies", "sources", "executions", ]); const pluginExtensions = Object.fromEntries( Object.entries(executor) .filter(([key]) => !coreKeys.has(key)) .map(([key, value]) => [key, promiseifyValue(value)]), ); return Object.assign(base, pluginExtensions) as unknown as Executor; }; export const createExecutor = async < const TPlugins extends readonly ExecutorSdkPlugin[] = [], >( options: CreateExecutorOptions, ): Promise> => toPromiseExecutor( await Effect.runPromise(createExecutorEffect(options)), );