mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 14:29:45 +00:00
Refactor/actions (#2733)
* store, properties, manifest * interfaces * init and backups * fix init and backups * file models * more versions * dependencies * config except dynamic types * clean up config * remove disabled from non-dynamic vaues * actions * standardize example code block formats * wip: actions refactor Co-authored-by: Jade <Blu-J@users.noreply.github.com> * commit types * fix types * update types * update action request type * update apis * add description to actionrequest * clean up imports * revert package json * chore: Remove the recursive to the index * chore: Remove the other thing I was testing * flatten action requests * update container runtime with new config paradigm * new actions strategy * seems to be working * misc backend fixes * fix fe bugs * only show breakages if breakages * only show success modal if result * don't panic on failed removal * hide config from actions page * polyfill autoconfig * use metadata strategy for actions instead of prev * misc fixes * chore: split the sdk into 2 libs (#2736) * follow sideload progress (#2718) * follow sideload progress * small bugfix * shareReplay with no refcount false * don't wrap sideload progress in RPCResult * dont present toast --------- Co-authored-by: Aiden McClelland <me@drbonez.dev> * chore: Add the initial of the creation of the two sdk * chore: Add in the baseDist * chore: Add in the baseDist * chore: Get the web and the runtime-container running * chore: Remove the empty file * chore: Fix it so the container-runtime works --------- Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com> Co-authored-by: Aiden McClelland <me@drbonez.dev> * misc fixes * update todos * minor clean up * fix link script * update node version in CI test * fix node version syntax in ci build * wip: fixing callbacks * fix sdk makefile dependencies * add support for const outside of main * update apis * don't panic! * Chore: Capture weird case on rpc, and log that * fix procedure id issue * pass input value for dep auto config * handle disabled and warning for actions * chore: Fix for link not having node_modules * sdk fixes * fix build * fix build * fix build --------- Co-authored-by: Matt Hill <mattnine@protonmail.com> Co-authored-by: Jade <Blu-J@users.noreply.github.com> Co-authored-by: J H <dragondef@gmail.com> Co-authored-by: Jade <2364004+Blu-J@users.noreply.github.com> Co-authored-by: Matt Hill <MattDHill@users.noreply.github.com>
This commit is contained in:
152
sdk/base/lib/actions/setupActions.ts
Normal file
152
sdk/base/lib/actions/setupActions.ts
Normal file
@@ -0,0 +1,152 @@
|
||||
import { InputSpec } from "./input/builder"
|
||||
import { ExtractInputSpecType } from "./input/builder/inputSpec"
|
||||
import * as T from "../types"
|
||||
|
||||
export type Run<
|
||||
A extends
|
||||
| Record<string, any>
|
||||
| InputSpec<Record<string, any>, any>
|
||||
| InputSpec<Record<string, never>, never>,
|
||||
> = (options: {
|
||||
effects: T.Effects
|
||||
input: ExtractInputSpecType<A> & Record<string, any>
|
||||
}) => Promise<T.ActionResult | null>
|
||||
export type GetInput<
|
||||
A extends
|
||||
| Record<string, any>
|
||||
| InputSpec<Record<string, any>, any>
|
||||
| InputSpec<Record<string, any>, never>,
|
||||
> = (options: {
|
||||
effects: T.Effects
|
||||
}) => Promise<null | (ExtractInputSpecType<A> & Record<string, any>)>
|
||||
|
||||
export type MaybeFn<T> = T | ((options: { effects: T.Effects }) => Promise<T>)
|
||||
function callMaybeFn<T>(
|
||||
maybeFn: MaybeFn<T>,
|
||||
options: { effects: T.Effects },
|
||||
): Promise<T> {
|
||||
if (maybeFn instanceof Function) {
|
||||
return maybeFn(options)
|
||||
} else {
|
||||
return Promise.resolve(maybeFn)
|
||||
}
|
||||
}
|
||||
function mapMaybeFn<T, U>(
|
||||
maybeFn: MaybeFn<T>,
|
||||
map: (value: T) => U,
|
||||
): MaybeFn<U> {
|
||||
if (maybeFn instanceof Function) {
|
||||
return async (...args) => map(await maybeFn(...args))
|
||||
} else {
|
||||
return map(maybeFn)
|
||||
}
|
||||
}
|
||||
|
||||
export class Action<
|
||||
Id extends T.ActionId,
|
||||
Store,
|
||||
InputSpecType extends
|
||||
| Record<string, any>
|
||||
| InputSpec<any, Store>
|
||||
| InputSpec<any, never>,
|
||||
Type extends
|
||||
ExtractInputSpecType<InputSpecType> = ExtractInputSpecType<InputSpecType>,
|
||||
> {
|
||||
private constructor(
|
||||
readonly id: Id,
|
||||
private readonly metadataFn: MaybeFn<T.ActionMetadata>,
|
||||
private readonly inputSpec: InputSpecType,
|
||||
private readonly getInputFn: GetInput<Type>,
|
||||
private readonly runFn: Run<Type>,
|
||||
) {}
|
||||
static withInput<
|
||||
Id extends T.ActionId,
|
||||
Store,
|
||||
InputSpecType extends
|
||||
| Record<string, any>
|
||||
| InputSpec<any, Store>
|
||||
| InputSpec<any, never>,
|
||||
Type extends
|
||||
ExtractInputSpecType<InputSpecType> = ExtractInputSpecType<InputSpecType>,
|
||||
>(
|
||||
id: Id,
|
||||
metadata: MaybeFn<Omit<T.ActionMetadata, "hasInput">>,
|
||||
inputSpec: InputSpecType,
|
||||
getInput: GetInput<Type>,
|
||||
run: Run<Type>,
|
||||
): Action<Id, Store, InputSpecType, Type> {
|
||||
return new Action(
|
||||
id,
|
||||
mapMaybeFn(metadata, (m) => ({ ...m, hasInput: true })),
|
||||
inputSpec,
|
||||
getInput,
|
||||
run,
|
||||
)
|
||||
}
|
||||
static withoutInput<Id extends T.ActionId, Store>(
|
||||
id: Id,
|
||||
metadata: MaybeFn<Omit<T.ActionMetadata, "hasInput">>,
|
||||
run: Run<{}>,
|
||||
): Action<Id, Store, {}, {}> {
|
||||
return new Action(
|
||||
id,
|
||||
mapMaybeFn(metadata, (m) => ({ ...m, hasInput: true })),
|
||||
{},
|
||||
async () => null,
|
||||
run,
|
||||
)
|
||||
}
|
||||
async exportMetadata(options: {
|
||||
effects: T.Effects
|
||||
}): Promise<T.ActionMetadata> {
|
||||
const metadata = await callMaybeFn(this.metadataFn, options)
|
||||
await options.effects.action.export({ id: this.id, metadata })
|
||||
return metadata
|
||||
}
|
||||
async getInput(options: { effects: T.Effects }): Promise<T.ActionInput> {
|
||||
return {
|
||||
spec: await this.inputSpec.build(options),
|
||||
value: (await this.getInputFn(options)) || null,
|
||||
}
|
||||
}
|
||||
async run(options: {
|
||||
effects: T.Effects
|
||||
input: Type
|
||||
}): Promise<T.ActionResult | null> {
|
||||
return this.runFn(options)
|
||||
}
|
||||
}
|
||||
|
||||
export class Actions<
|
||||
Store,
|
||||
AllActions extends Record<T.ActionId, Action<T.ActionId, Store, any, any>>,
|
||||
> {
|
||||
private constructor(private readonly actions: AllActions) {}
|
||||
static of<Store>(): Actions<Store, {}> {
|
||||
return new Actions({})
|
||||
}
|
||||
addAction<A extends Action<T.ActionId, Store, any, any>>(
|
||||
action: A,
|
||||
): Actions<Store, AllActions & { [id in A["id"]]: A }> {
|
||||
return new Actions({ ...this.actions, [action.id]: action })
|
||||
}
|
||||
update(options: { effects: T.Effects }): Promise<void> {
|
||||
const updater = async (options: { effects: T.Effects }) => {
|
||||
for (let action of Object.values(this.actions)) {
|
||||
await action.exportMetadata(options)
|
||||
}
|
||||
await options.effects.action.clear({ except: Object.keys(this.actions) })
|
||||
}
|
||||
const updaterCtx = { options }
|
||||
updaterCtx.options = {
|
||||
effects: {
|
||||
...options.effects,
|
||||
constRetry: () => updater(updaterCtx.options),
|
||||
},
|
||||
}
|
||||
return updater(updaterCtx.options)
|
||||
}
|
||||
get<Id extends T.ActionId>(actionId: Id): AllActions[Id] {
|
||||
return this.actions[actionId]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user