mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
backend changes
This commit is contained in:
@@ -27,6 +27,7 @@ import {
|
||||
/** Used to reach out from the pure js runtime */
|
||||
|
||||
export type Effects = {
|
||||
readonly eventId: string | null
|
||||
child: (name: string) => Effects
|
||||
constRetry?: () => void
|
||||
isInContext: boolean
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import { ExtractInputSpecType, InputSpec, LazyBuild } from "./inputSpec"
|
||||
import { InputSpec, LazyBuild } from "./inputSpec"
|
||||
import { List } from "./list"
|
||||
import { UnionRes, UnionResStaticValidatedAs, Variants } from "./variants"
|
||||
import {
|
||||
FilePath,
|
||||
Pattern,
|
||||
RandomString,
|
||||
ValueSpec,
|
||||
@@ -27,6 +26,12 @@ import {
|
||||
} from "ts-matches"
|
||||
import { DeepPartial } from "../../../types"
|
||||
|
||||
export const fileInfoParser = object({
|
||||
path: string,
|
||||
commitment: object({ hash: string, size: number }),
|
||||
})
|
||||
export type FileInfo = typeof fileInfoParser._TYPE
|
||||
|
||||
type AsRequired<T, Required extends boolean> = Required extends true
|
||||
? T
|
||||
: T | null
|
||||
@@ -891,47 +896,54 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
}
|
||||
}, spec.validator)
|
||||
}
|
||||
// static file<Store, Required extends boolean>(a: {
|
||||
// name: string
|
||||
// description?: string | null
|
||||
// extensions: string[]
|
||||
// required: Required
|
||||
// }) {
|
||||
// const buildValue = {
|
||||
// type: "file" as const,
|
||||
// description: null,
|
||||
// warning: null,
|
||||
// ...a,
|
||||
// }
|
||||
// return new Value<AsRequired<FilePath, Required>, Store>(
|
||||
// () => ({
|
||||
// ...buildValue,
|
||||
// }),
|
||||
// asRequiredParser(object({ filePath: string }), a),
|
||||
// )
|
||||
// }
|
||||
// static dynamicFile<Store>(
|
||||
// a: LazyBuild<
|
||||
// Store,
|
||||
// {
|
||||
// name: string
|
||||
// description?: string | null
|
||||
// warning?: string | null
|
||||
// extensions: string[]
|
||||
// required: boolean
|
||||
// }
|
||||
// >,
|
||||
// ) {
|
||||
// return new Value<FilePath | null, Store>(
|
||||
// async (options) => ({
|
||||
// type: "file" as const,
|
||||
// description: null,
|
||||
// warning: null,
|
||||
// ...(await a(options)),
|
||||
// }),
|
||||
// object({ filePath: string }).nullable(),
|
||||
// )
|
||||
// }
|
||||
static file<Required extends boolean>(a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
extensions: string[]
|
||||
required: Required
|
||||
}) {
|
||||
const buildValue = {
|
||||
type: "file" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...a,
|
||||
}
|
||||
return new Value<AsRequired<FileInfo, Required>>(
|
||||
() => ({
|
||||
spec: {
|
||||
...buildValue,
|
||||
},
|
||||
validator: asRequiredParser(fileInfoParser, a),
|
||||
}),
|
||||
asRequiredParser(fileInfoParser, a),
|
||||
)
|
||||
}
|
||||
static dynamicFile<Required extends boolean>(
|
||||
a: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
extensions: string[]
|
||||
required: Required
|
||||
}>,
|
||||
) {
|
||||
return new Value<AsRequired<FileInfo, Required>, FileInfo | null>(
|
||||
async (options) => {
|
||||
const spec = {
|
||||
type: "file" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...(await a(options)),
|
||||
}
|
||||
return {
|
||||
spec,
|
||||
validator: asRequiredParser(fileInfoParser, spec),
|
||||
}
|
||||
},
|
||||
fileInfoParser.nullable(),
|
||||
)
|
||||
}
|
||||
/**
|
||||
* @description Displays a dropdown, allowing for a single selection. Depending on the selection, a different object ("sub form") is presented.
|
||||
* @example
|
||||
|
||||
@@ -66,9 +66,6 @@ export type ValueSpecTextarea = {
|
||||
immutable: boolean
|
||||
}
|
||||
|
||||
export type FilePath = {
|
||||
filePath: string
|
||||
}
|
||||
export type ValueSpecNumber = {
|
||||
type: "number"
|
||||
min: number | null
|
||||
|
||||
@@ -5,9 +5,11 @@ import { once } from "../util"
|
||||
import { InitScript } from "../inits"
|
||||
import { Parser } from "ts-matches"
|
||||
|
||||
type MaybeInputSpec<Type> = {} extends Type ? null : InputSpec<Type>
|
||||
export type Run<A extends Record<string, any>> = (options: {
|
||||
effects: T.Effects
|
||||
input: A
|
||||
spec: T.inputSpecTypes.InputSpec
|
||||
}) => Promise<(T.ActionResult & { version: "1" }) | null | void | undefined>
|
||||
export type GetInput<A extends Record<string, any>> = (options: {
|
||||
effects: T.Effects
|
||||
@@ -47,11 +49,14 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
implements ActionInfo<Id, Type>
|
||||
{
|
||||
readonly _INPUT: Type = null as any as Type
|
||||
private cachedParser?: Parser<unknown, Type>
|
||||
private prevInputSpec: Record<
|
||||
string,
|
||||
{ spec: T.inputSpecTypes.InputSpec; validator: Parser<unknown, Type> }
|
||||
> = {}
|
||||
private constructor(
|
||||
readonly id: Id,
|
||||
private readonly metadataFn: MaybeFn<T.ActionMetadata>,
|
||||
private readonly inputSpec: InputSpec<Type>,
|
||||
private readonly inputSpec: MaybeInputSpec<Type>,
|
||||
private readonly getInputFn: GetInput<Type>,
|
||||
private readonly runFn: Run<Type>,
|
||||
) {}
|
||||
@@ -81,7 +86,7 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
return new Action(
|
||||
id,
|
||||
mapMaybeFn(metadata, (m) => ({ ...m, hasInput: false })),
|
||||
InputSpec.of({}),
|
||||
null,
|
||||
async () => null,
|
||||
run,
|
||||
)
|
||||
@@ -100,10 +105,15 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
return metadata
|
||||
}
|
||||
async getInput(options: { effects: T.Effects }): Promise<T.ActionInput> {
|
||||
const built = await this.inputSpec.build(options)
|
||||
this.cachedParser = built.validator
|
||||
let spec = {}
|
||||
if (this.inputSpec) {
|
||||
const built = await this.inputSpec.build(options)
|
||||
this.prevInputSpec[options.effects.eventId!] = built
|
||||
spec = built.spec
|
||||
}
|
||||
return {
|
||||
spec: built.spec,
|
||||
eventId: options.effects.eventId!,
|
||||
spec,
|
||||
value:
|
||||
((await this.getInputFn(options)) as
|
||||
| Record<string, unknown>
|
||||
@@ -115,15 +125,23 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
effects: T.Effects
|
||||
input: Type
|
||||
}): Promise<T.ActionResult | null> {
|
||||
const parser =
|
||||
this.cachedParser ?? (await this.inputSpec.build(options)).validator
|
||||
let spec = {}
|
||||
if (this.inputSpec) {
|
||||
const prevInputSpec = this.prevInputSpec[options.effects.eventId!]
|
||||
if (!prevInputSpec) {
|
||||
throw new Error(
|
||||
`getActionInput has not been called for EventID ${options.effects.eventId}`,
|
||||
)
|
||||
}
|
||||
options.input = prevInputSpec.validator.unsafeCast(options.input)
|
||||
spec = prevInputSpec.spec
|
||||
}
|
||||
return (
|
||||
(await this.runFn({
|
||||
effects: options.effects,
|
||||
input: this.cachedParser
|
||||
? this.cachedParser.unsafeCast(options.input)
|
||||
: options.input,
|
||||
})) || null
|
||||
input: options.input,
|
||||
spec,
|
||||
})) ?? null
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Guid } from "./Guid"
|
||||
|
||||
export type ActionInput = {
|
||||
eventId: Guid
|
||||
spec: Record<string, unknown>
|
||||
value: Record<string, unknown> | null
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually.
|
||||
import type { Guid } from "./Guid"
|
||||
|
||||
export type ProcedureId = { procedureId: Guid }
|
||||
export type EventId = { eventId: Guid }
|
||||
@@ -2,7 +2,6 @@
|
||||
import type { IpInfo } from "./IpInfo"
|
||||
|
||||
export type NetworkInterfaceInfo = {
|
||||
inbound: boolean | null
|
||||
outbound: boolean | null
|
||||
public: boolean | null
|
||||
ipInfo: IpInfo | null
|
||||
}
|
||||
|
||||
@@ -70,6 +70,7 @@ export { Duration } from "./Duration"
|
||||
export { EchoParams } from "./EchoParams"
|
||||
export { EditSignerParams } from "./EditSignerParams"
|
||||
export { EncryptedWire } from "./EncryptedWire"
|
||||
export { EventId } from "./EventId"
|
||||
export { ExportActionParams } from "./ExportActionParams"
|
||||
export { ExportServiceInterfaceParams } from "./ExportServiceInterfaceParams"
|
||||
export { FileType } from "./FileType"
|
||||
@@ -155,7 +156,6 @@ export { PackageVersionInfo } from "./PackageVersionInfo"
|
||||
export { PasswordType } from "./PasswordType"
|
||||
export { PathOrUrl } from "./PathOrUrl"
|
||||
export { Percentage } from "./Percentage"
|
||||
export { ProcedureId } from "./ProcedureId"
|
||||
export { Progress } from "./Progress"
|
||||
export { ProgressUnits } from "./ProgressUnits"
|
||||
export { Public } from "./Public"
|
||||
|
||||
@@ -46,6 +46,7 @@ type EffectsTypeChecker<T extends StringObject = Effects> = {
|
||||
describe("startosTypeValidation ", () => {
|
||||
test(`checking the params match`, () => {
|
||||
typeEquality<EffectsTypeChecker>({
|
||||
eventId: {} as never,
|
||||
child: "",
|
||||
isInContext: {} as never,
|
||||
onLeaveContext: () => {},
|
||||
|
||||
@@ -104,7 +104,7 @@ export class StartSdk<Manifest extends T.SDKManifest> {
|
||||
|
||||
// prettier-ignore
|
||||
type StartSdkEffectWrapper = {
|
||||
[K in keyof Omit<Effects, NestedEffects | InterfaceEffects | MainUsedEffects | CallbackEffects | AlreadyExposed>]: (effects: Effects, ...args: Parameters<Effects[K]>) => ReturnType<Effects[K]>
|
||||
[K in keyof Omit<Effects, "eventId" | NestedEffects | InterfaceEffects | MainUsedEffects | CallbackEffects | AlreadyExposed>]: (effects: Effects, ...args: Parameters<Effects[K]>) => ReturnType<Effects[K]>
|
||||
}
|
||||
const startSdkEffectWrapper: StartSdkEffectWrapper = {
|
||||
restart: (effects, ...args) => effects.restart(...args),
|
||||
|
||||
Reference in New Issue
Block a user