diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index d3e36ec..467b9fc 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -11,16 +11,15 @@ export class CreatedAction< Type extends Record = ExtractConfigType, > { private constructor( - public readonly myMetaData: Omit & { - input: Config - }, + public readonly myMetaData: ActionMetaData, readonly fn: (options: { effects: Effects utils: Utils input: Type }) => Promise, + readonly input: Config | Config, ) {} - private validator = this.myMetaData.input.validator + public validator = this.input.validator static of< WrapperData, @@ -36,7 +35,8 @@ export class CreatedAction< input: Type }) => Promise, ) { - return new CreatedAction(metaData, fn) + const { input, ...rest } = metaData + return new CreatedAction(rest, fn, input) } exportedAction: ExportedAction = ({ effects, input }) => { @@ -47,16 +47,19 @@ export class CreatedAction< }) } - async exportAction(effects: Effects) { - const myUtils = utils(effects) - const metaData = { - ...this.myMetaData, - input: await this.myMetaData.input.build({ - effects, - utils: myUtils, - }), - } - await effects.exportAction(metaData) + run = async ({ effects, input }: { effects: Effects; input?: Type }) => { + return this.fn({ + effects, + utils: utils(effects), + input: this.validator.unsafeCast(input), + }) + } + + async getConfig({ effects }: { effects: Effects }) { + return this.input.build({ + effects, + utils: utils(effects) as any, + }) } } diff --git a/lib/actions/setupActions.ts b/lib/actions/setupActions.ts index c93ad44..5efc844 100644 --- a/lib/actions/setupActions.ts +++ b/lib/actions/setupActions.ts @@ -1,15 +1,19 @@ import { Effects, ExpectedExports, ExportedAction } from "../types" import { ActionMetaData } from "../types" +import { once } from "../util/once" import { CreatedAction } from "./createAction" export function setupActions(...createdActions: CreatedAction[]) { + const myActions = once(() => { + const actions: Record> = {} + for (const action of createdActions) { + actions[action.myMetaData.id] = action + } + return actions + }) return { get actions() { - const actions: Record = {} - for (const action of createdActions) { - actions[action.myMetaData.id] = action.exportedAction - } - return actions + return myActions() }, get actionsMetadata() { return createdActions.map((x) => x.myMetaData) diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index ca1118f..6d725de 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -627,12 +627,15 @@ export class Value { static filteredUnion( getDisabledFn: LazyBuild, ) { - return >( + return < + Required extends RequiredDefault, + Type extends Record, + >( a: { name: string description?: string | null warning?: string | null - required: RequiredDefault + required: Required default?: string | null }, aVariants: Variants | Variants, diff --git a/lib/config/constants.ts b/lib/config/constants.ts index b2e4002..c098b12 100644 --- a/lib/config/constants.ts +++ b/lib/config/constants.ts @@ -59,3 +59,4 @@ export const smtpConfig = Value.filteredUnion(async ({ effects, utils }) => { }, }), ) +type test = typeof smtpConfig.validator._TYPE diff --git a/lib/types.ts b/lib/types.ts index 26b700e..24a3984 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -43,7 +43,10 @@ export namespace ExpectedExports { * service starting, and that file would indicate that it would rescan all the data. */ export type actions = { - [id: string]: ExportedAction + [id: string]: { + run: ExportedAction + getConfig: (options: { effects: Effects }) => Promise + } } /** @@ -155,7 +158,6 @@ export type ActionMetaData = { name: string description: string id: string - input: null | InputSpec runningOnly: boolean /** * So the ordering of the actions is by alphabetical order of the group, then followed by the alphabetical of the actions @@ -424,6 +426,26 @@ export type Effects = { exists(packageId: PackageId): Promise /** Exists could be useful during the runtime to know if some service is running, option dep */ running(packageId: PackageId): Promise + + /** Instead of creating proxies with nginx, we have a utility to create and maintain a proxy in the lifetime of this running. */ + reverseProxy(options: { + bind: { + /** Optional, default is 0.0.0.0 */ + ip?: string + port: number + ssl: boolean + } + dst: { + /** Optional: default is 127.0.0.1 */ + ip?: string // optional, default 127.0.0.1 + port: number + ssl: boolean + } + http: { + // optional, will do TCP layer proxy only if not present + headers: (headers: Record) => Record + } + }): Promise<{ stop(): Promise }> restart(): void shutdown(): void }