mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
feat: builder-style InputSpec API, prefill plumbing, and port forward fix
- Add addKey() and add() builder methods to InputSpec with InputSpecTools - Move OuterType to last generic param on Value, List, and all dynamic methods - Plumb prefill through getActionInput end-to-end (core → container-runtime → SDK) - Filter port_forwards to enabled addresses only - Bump SDK to 0.4.0-beta.50
This commit is contained in:
2
container-runtime/package-lock.json
generated
2
container-runtime/package-lock.json
generated
@@ -38,7 +38,7 @@
|
||||
},
|
||||
"../sdk/dist": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.49",
|
||||
"version": "0.4.0-beta.50",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^3.0.0",
|
||||
|
||||
@@ -437,6 +437,7 @@ export class RpcListener {
|
||||
return system.getActionInput(
|
||||
effects,
|
||||
procedures[2],
|
||||
input?.prefill ?? null,
|
||||
timeout || null,
|
||||
)
|
||||
case procedures[1] === "actions" && procedures[3] === "run":
|
||||
|
||||
@@ -510,6 +510,7 @@ export class SystemForEmbassy implements System {
|
||||
async getActionInput(
|
||||
effects: Effects,
|
||||
actionId: string,
|
||||
_prefill: Record<string, unknown> | null,
|
||||
timeoutMs: number | null,
|
||||
): Promise<T.ActionInput | null> {
|
||||
if (actionId === "config") {
|
||||
|
||||
@@ -47,11 +47,12 @@ export class SystemForStartOs implements System {
|
||||
getActionInput(
|
||||
effects: Effects,
|
||||
id: string,
|
||||
prefill: Record<string, unknown> | null,
|
||||
timeoutMs: number | null,
|
||||
): Promise<T.ActionInput | null> {
|
||||
const action = this.abi.actions.get(id)
|
||||
if (!action) throw new Error(`Action ${id} not found`)
|
||||
return action.getInput({ effects })
|
||||
return action.getInput({ effects, prefill })
|
||||
}
|
||||
runAction(
|
||||
effects: Effects,
|
||||
|
||||
@@ -33,6 +33,7 @@ export type System = {
|
||||
getActionInput(
|
||||
effects: Effects,
|
||||
actionId: string,
|
||||
prefill: Record<string, unknown> | null,
|
||||
timeoutMs: number | null,
|
||||
): Promise<T.ActionInput | null>
|
||||
|
||||
|
||||
@@ -67,6 +67,10 @@ pub struct GetActionInputParams {
|
||||
pub package_id: PackageId,
|
||||
#[arg(help = "help.arg.action-id")]
|
||||
pub action_id: ActionId,
|
||||
#[ts(type = "Record<string, unknown> | null")]
|
||||
#[serde(default)]
|
||||
#[arg(skip)]
|
||||
pub prefill: Option<Value>,
|
||||
}
|
||||
|
||||
#[instrument(skip_all)]
|
||||
@@ -75,6 +79,7 @@ pub async fn get_action_input(
|
||||
GetActionInputParams {
|
||||
package_id,
|
||||
action_id,
|
||||
prefill,
|
||||
}: GetActionInputParams,
|
||||
) -> Result<Option<ActionInput>, Error> {
|
||||
ctx.services
|
||||
@@ -82,7 +87,7 @@ pub async fn get_action_input(
|
||||
.await
|
||||
.as_ref()
|
||||
.or_not_found(lazy_format!("Manager for {}", package_id))?
|
||||
.get_action_input(Guid::new(), action_id)
|
||||
.get_action_input(Guid::new(), action_id, prefill.unwrap_or(Value::Null))
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -533,7 +533,7 @@ impl RpcContext {
|
||||
for (package_id, action_id) in tasks {
|
||||
if let Some(service) = self.services.get(&package_id).await.as_ref() {
|
||||
if let Some(input) = service
|
||||
.get_action_input(procedure_id.clone(), action_id.clone())
|
||||
.get_action_input(procedure_id.clone(), action_id.clone(), Value::Null)
|
||||
.await
|
||||
.log_err()
|
||||
.flatten()
|
||||
|
||||
@@ -298,7 +298,7 @@ impl Model<Host> {
|
||||
let bindings: Bindings = this.bindings.de()?;
|
||||
let mut port_forwards = BTreeSet::new();
|
||||
for bind in bindings.values() {
|
||||
for addr in &bind.addresses.available {
|
||||
for addr in bind.addresses.enabled() {
|
||||
if !addr.public {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ use crate::{ActionId, PackageId, ReplayId};
|
||||
|
||||
pub(super) struct GetActionInput {
|
||||
id: ActionId,
|
||||
prefill: Value,
|
||||
}
|
||||
impl Handler<GetActionInput> for ServiceActor {
|
||||
type Response = Result<Option<ActionInput>, Error>;
|
||||
@@ -26,7 +27,10 @@ impl Handler<GetActionInput> for ServiceActor {
|
||||
async fn handle(
|
||||
&mut self,
|
||||
id: Guid,
|
||||
GetActionInput { id: action_id }: GetActionInput,
|
||||
GetActionInput {
|
||||
id: action_id,
|
||||
prefill,
|
||||
}: GetActionInput,
|
||||
_: &BackgroundJobQueue,
|
||||
) -> Self::Response {
|
||||
let container = &self.0.persistent_container;
|
||||
@@ -34,7 +38,7 @@ impl Handler<GetActionInput> for ServiceActor {
|
||||
.execute::<Option<ActionInput>>(
|
||||
id,
|
||||
ProcedureName::GetActionInput(action_id),
|
||||
Value::Null,
|
||||
json!({ "prefill": prefill }),
|
||||
Some(Duration::from_secs(30)),
|
||||
)
|
||||
.await
|
||||
@@ -47,6 +51,7 @@ impl Service {
|
||||
&self,
|
||||
id: Guid,
|
||||
action_id: ActionId,
|
||||
prefill: Value,
|
||||
) -> Result<Option<ActionInput>, Error> {
|
||||
if !self
|
||||
.seed
|
||||
@@ -67,7 +72,7 @@ impl Service {
|
||||
return Ok(None);
|
||||
}
|
||||
self.actor
|
||||
.send(id, GetActionInput { id: action_id })
|
||||
.send(id, GetActionInput { id: action_id, prefill })
|
||||
.await?
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,10 @@ pub struct GetActionInputParams {
|
||||
package_id: Option<PackageId>,
|
||||
#[arg(help = "help.arg.action-id")]
|
||||
action_id: ActionId,
|
||||
#[ts(type = "Record<string, unknown> | null")]
|
||||
#[serde(default)]
|
||||
#[arg(skip)]
|
||||
prefill: Option<Value>,
|
||||
}
|
||||
async fn get_action_input(
|
||||
context: EffectContext,
|
||||
@@ -129,9 +133,11 @@ async fn get_action_input(
|
||||
procedure_id,
|
||||
package_id,
|
||||
action_id,
|
||||
prefill,
|
||||
}: GetActionInputParams,
|
||||
) -> Result<Option<ActionInput>, Error> {
|
||||
let context = context.deref()?;
|
||||
let prefill = prefill.unwrap_or(Value::Null);
|
||||
|
||||
if let Some(package_id) = package_id {
|
||||
context
|
||||
@@ -142,10 +148,10 @@ async fn get_action_input(
|
||||
.await
|
||||
.as_ref()
|
||||
.or_not_found(&package_id)?
|
||||
.get_action_input(procedure_id, action_id)
|
||||
.get_action_input(procedure_id, action_id, prefill)
|
||||
.await
|
||||
} else {
|
||||
context.get_action_input(procedure_id, action_id).await
|
||||
context.get_action_input(procedure_id, action_id, prefill).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,7 +251,7 @@ async fn create_task(
|
||||
.as_ref()
|
||||
{
|
||||
let Some(prev) = service
|
||||
.get_action_input(procedure_id.clone(), task.action_id.clone())
|
||||
.get_action_input(procedure_id.clone(), task.action_id.clone(), Value::Null)
|
||||
.await?
|
||||
else {
|
||||
return Err(Error::new(
|
||||
|
||||
@@ -534,7 +534,7 @@ impl Service {
|
||||
.contains_key(&action_id)?
|
||||
{
|
||||
if let Some(input) = service
|
||||
.get_action_input(procedure_id.clone(), action_id.clone())
|
||||
.get_action_input(procedure_id.clone(), action_id.clone(), Value::Null)
|
||||
.await
|
||||
.log_err()
|
||||
.flatten()
|
||||
|
||||
@@ -4,12 +4,14 @@ import { _ } from '../../../util'
|
||||
import { Effects } from '../../../Effects'
|
||||
import { Parser, object } from 'ts-matches'
|
||||
import { DeepPartial } from '../../../types'
|
||||
import { InputSpecTools, createInputSpecTools } from './inputSpecTools'
|
||||
|
||||
export type LazyBuildOptions = {
|
||||
export type LazyBuildOptions<Type> = {
|
||||
effects: Effects
|
||||
prefill: DeepPartial<Type> | null
|
||||
}
|
||||
export type LazyBuild<ExpectedOut> = (
|
||||
options: LazyBuildOptions,
|
||||
export type LazyBuild<ExpectedOut, Type> = (
|
||||
options: LazyBuildOptions<Type>,
|
||||
) => Promise<ExpectedOut> | ExpectedOut
|
||||
|
||||
// prettier-ignore
|
||||
@@ -29,7 +31,7 @@ export type InputSpecOf<A extends Record<string, any>> = {
|
||||
[K in keyof A]: Value<A[K]>
|
||||
}
|
||||
|
||||
export type MaybeLazyValues<A> = LazyBuild<A> | A
|
||||
export type MaybeLazyValues<A, T> = LazyBuild<A, T> | A
|
||||
/**
|
||||
* InputSpecs are the specs that are used by the os input specification form for this service.
|
||||
* Here is an example of a simple input specification
|
||||
@@ -98,7 +100,7 @@ export class InputSpec<
|
||||
) {}
|
||||
public _TYPE: Type = null as any as Type
|
||||
public _PARTIAL: DeepPartial<Type> = null as any as DeepPartial<Type>
|
||||
async build(options: LazyBuildOptions): Promise<{
|
||||
async build<OuterType>(options: LazyBuildOptions<OuterType>): Promise<{
|
||||
spec: {
|
||||
[K in keyof Type]: ValueSpec
|
||||
}
|
||||
@@ -121,6 +123,57 @@ export class InputSpec<
|
||||
}
|
||||
}
|
||||
|
||||
addKey<Key extends string, V extends Value<any, any, any>>(
|
||||
key: Key,
|
||||
build: V | ((tools: InputSpecTools<Type>) => V),
|
||||
): InputSpec<
|
||||
Type & { [K in Key]: V extends Value<infer T, any, any> ? T : never },
|
||||
StaticValidatedAs & {
|
||||
[K in Key]: V extends Value<any, infer S, any> ? S : never
|
||||
}
|
||||
> {
|
||||
const value =
|
||||
build instanceof Function ? build(createInputSpecTools<Type>()) : build
|
||||
const newSpec = { ...this.spec, [key]: value } as any
|
||||
const newValidator = object(
|
||||
Object.fromEntries(
|
||||
Object.entries(newSpec).map(([k, v]) => [
|
||||
k,
|
||||
(v as Value<any>).validator,
|
||||
]),
|
||||
),
|
||||
)
|
||||
return new InputSpec(newSpec, newValidator as any)
|
||||
}
|
||||
|
||||
add<AddSpec extends Record<string, Value<any, any, any>>>(
|
||||
build: AddSpec | ((tools: InputSpecTools<Type>) => AddSpec),
|
||||
): InputSpec<
|
||||
Type & {
|
||||
[K in keyof AddSpec]: AddSpec[K] extends Value<infer T, any, any>
|
||||
? T
|
||||
: never
|
||||
},
|
||||
StaticValidatedAs & {
|
||||
[K in keyof AddSpec]: AddSpec[K] extends Value<any, infer S, any>
|
||||
? S
|
||||
: never
|
||||
}
|
||||
> {
|
||||
const addedValues =
|
||||
build instanceof Function ? build(createInputSpecTools<Type>()) : build
|
||||
const newSpec = { ...this.spec, ...addedValues } as any
|
||||
const newValidator = object(
|
||||
Object.fromEntries(
|
||||
Object.entries(newSpec).map(([k, v]) => [
|
||||
k,
|
||||
(v as Value<any>).validator,
|
||||
]),
|
||||
),
|
||||
)
|
||||
return new InputSpec(newSpec, newValidator as any)
|
||||
}
|
||||
|
||||
static of<Spec extends Record<string, Value<any, any>>>(spec: Spec) {
|
||||
const validator = object(
|
||||
Object.fromEntries(
|
||||
@@ -129,10 +182,14 @@ export class InputSpec<
|
||||
)
|
||||
return new InputSpec<
|
||||
{
|
||||
[K in keyof Spec]: Spec[K] extends Value<infer T, any> ? T : never
|
||||
[K in keyof Spec]: Spec[K] extends Value<infer T, any, unknown>
|
||||
? T
|
||||
: never
|
||||
},
|
||||
{
|
||||
[K in keyof Spec]: Spec[K] extends Value<any, infer T> ? T : never
|
||||
[K in keyof Spec]: Spec[K] extends Value<any, infer T, unknown>
|
||||
? T
|
||||
: never
|
||||
}
|
||||
>(spec, validator as any)
|
||||
}
|
||||
|
||||
274
sdk/base/lib/actions/input/builder/inputSpecTools.ts
Normal file
274
sdk/base/lib/actions/input/builder/inputSpecTools.ts
Normal file
@@ -0,0 +1,274 @@
|
||||
import { InputSpec, LazyBuild } from './inputSpec'
|
||||
import { AsRequired, FileInfo, Value } from './value'
|
||||
import { List } from './list'
|
||||
import { UnionRes, UnionResStaticValidatedAs, Variants } from './variants'
|
||||
import {
|
||||
Pattern,
|
||||
RandomString,
|
||||
ValueSpecDatetime,
|
||||
ValueSpecText,
|
||||
} from '../inputSpecTypes'
|
||||
import { DefaultString } from '../inputSpecTypes'
|
||||
import { Parser } from 'ts-matches'
|
||||
import { ListValueSpecText } from '../inputSpecTypes'
|
||||
|
||||
export interface InputSpecTools<OuterType> {
|
||||
Value: BoundValue<OuterType>
|
||||
Variants: typeof Variants
|
||||
InputSpec: typeof InputSpec
|
||||
List: BoundList<OuterType>
|
||||
}
|
||||
|
||||
export interface BoundValue<OuterType> {
|
||||
// Static (non-dynamic) methods — no OuterType involved
|
||||
toggle: typeof Value.toggle
|
||||
text: typeof Value.text
|
||||
textarea: typeof Value.textarea
|
||||
number: typeof Value.number
|
||||
color: typeof Value.color
|
||||
datetime: typeof Value.datetime
|
||||
select: typeof Value.select
|
||||
multiselect: typeof Value.multiselect
|
||||
object: typeof Value.object
|
||||
file: typeof Value.file
|
||||
list: typeof Value.list
|
||||
hidden: typeof Value.hidden
|
||||
union: typeof Value.union
|
||||
|
||||
// Dynamic methods with OuterType pre-bound (last generic param removed)
|
||||
dynamicToggle(
|
||||
a: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: boolean
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<boolean, boolean, OuterType>
|
||||
|
||||
dynamicText<Required extends boolean>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: DefaultString | null
|
||||
required: Required
|
||||
masked?: boolean
|
||||
placeholder?: string | null
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ValueSpecText['inputmode']
|
||||
disabled?: string | false
|
||||
generate?: null | RandomString
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<AsRequired<string, Required>, string | null, OuterType>
|
||||
|
||||
dynamicTextarea<Required extends boolean>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
minRows?: number
|
||||
maxRows?: number
|
||||
placeholder?: string | null
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<AsRequired<string, Required>, string | null, OuterType>
|
||||
|
||||
dynamicNumber<Required extends boolean>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: number | null
|
||||
required: Required
|
||||
min?: number | null
|
||||
max?: number | null
|
||||
step?: number | null
|
||||
integer: boolean
|
||||
units?: string | null
|
||||
placeholder?: string | null
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<AsRequired<number, Required>, number | null, OuterType>
|
||||
|
||||
dynamicColor<Required extends boolean>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<AsRequired<string, Required>, string | null, OuterType>
|
||||
|
||||
dynamicDatetime<Required extends boolean>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
inputmode?: ValueSpecDatetime['inputmode']
|
||||
min?: string | null
|
||||
max?: string | null
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<AsRequired<string, Required>, string | null, OuterType>
|
||||
|
||||
dynamicSelect<Values extends Record<string, string>>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string
|
||||
values: Values
|
||||
disabled?: false | string | string[]
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<keyof Values & string, keyof Values & string, OuterType>
|
||||
|
||||
dynamicMultiselect<Values extends Record<string, string>>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string[]
|
||||
values: Values
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
disabled?: false | string | string[]
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<(keyof Values & string)[], (keyof Values & string)[], OuterType>
|
||||
|
||||
dynamicFile<Required extends boolean>(
|
||||
a: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
extensions: string[]
|
||||
required: Required
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<AsRequired<FileInfo, Required>, FileInfo | null, OuterType>
|
||||
|
||||
dynamicUnion<
|
||||
VariantValues extends {
|
||||
[K in string]: {
|
||||
name: string
|
||||
spec: InputSpec<any>
|
||||
}
|
||||
},
|
||||
>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<UnionRes<VariantValues>, UnionRes<VariantValues>, OuterType>
|
||||
dynamicUnion<
|
||||
StaticVariantValues extends {
|
||||
[K in string]: {
|
||||
name: string
|
||||
spec: InputSpec<any, any>
|
||||
}
|
||||
},
|
||||
VariantValues extends StaticVariantValues,
|
||||
>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
validator: Parser<unknown, UnionResStaticValidatedAs<StaticVariantValues>>,
|
||||
): Value<
|
||||
UnionRes<VariantValues>,
|
||||
UnionResStaticValidatedAs<StaticVariantValues>,
|
||||
OuterType
|
||||
>
|
||||
|
||||
dynamicHidden<T>(
|
||||
getParser: LazyBuild<Parser<unknown, T>, OuterType>,
|
||||
): Value<T, T, OuterType>
|
||||
}
|
||||
|
||||
export interface BoundList<OuterType> {
|
||||
text: typeof List.text
|
||||
obj: typeof List.obj
|
||||
dynamicText(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default?: string[]
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
disabled?: false | string
|
||||
generate?: null | RandomString
|
||||
spec: {
|
||||
masked?: boolean
|
||||
placeholder?: string | null
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ListValueSpecText['inputmode']
|
||||
}
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): List<string[], string[], OuterType>
|
||||
}
|
||||
|
||||
export function createInputSpecTools<OuterType>(): InputSpecTools<OuterType> {
|
||||
return {
|
||||
Value: Value as any as BoundValue<OuterType>,
|
||||
Variants,
|
||||
InputSpec,
|
||||
List: List as any as BoundList<OuterType>,
|
||||
}
|
||||
}
|
||||
@@ -9,12 +9,19 @@ import {
|
||||
} from '../inputSpecTypes'
|
||||
import { Parser, arrayOf, string } from 'ts-matches'
|
||||
|
||||
export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
export class List<
|
||||
Type extends StaticValidatedAs,
|
||||
StaticValidatedAs = Type,
|
||||
OuterType = unknown,
|
||||
> {
|
||||
private constructor(
|
||||
public build: LazyBuild<{
|
||||
spec: ValueSpecList
|
||||
validator: Parser<unknown, Type>
|
||||
}>,
|
||||
public build: LazyBuild<
|
||||
{
|
||||
spec: ValueSpecList
|
||||
validator: Parser<unknown, Type>
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
public readonly validator: Parser<unknown, StaticValidatedAs>,
|
||||
) {}
|
||||
readonly _TYPE: Type = null as any
|
||||
@@ -90,28 +97,31 @@ export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
}, validator)
|
||||
}
|
||||
|
||||
static dynamicText(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default?: string[]
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
disabled?: false | string
|
||||
generate?: null | RandomString
|
||||
spec: {
|
||||
masked?: boolean
|
||||
placeholder?: string | null
|
||||
static dynamicText<OuterType = unknown>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default?: string[]
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ListValueSpecText['inputmode']
|
||||
}
|
||||
}>,
|
||||
disabled?: false | string
|
||||
generate?: null | RandomString
|
||||
spec: {
|
||||
masked?: boolean
|
||||
placeholder?: string | null
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ListValueSpecText['inputmode']
|
||||
}
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
const validator = arrayOf(string)
|
||||
return new List<string[]>(async (options) => {
|
||||
return new List<string[], string[], OuterType>(async (options) => {
|
||||
const { spec: aSpec, ...a } = await getA(options)
|
||||
const spec = {
|
||||
type: 'text' as const,
|
||||
|
||||
@@ -32,7 +32,7 @@ export const fileInfoParser = object({
|
||||
})
|
||||
export type FileInfo = typeof fileInfoParser._TYPE
|
||||
|
||||
type AsRequired<T, Required extends boolean> = Required extends true
|
||||
export type AsRequired<T, Required extends boolean> = Required extends true
|
||||
? T
|
||||
: T | null
|
||||
|
||||
@@ -47,12 +47,19 @@ function asRequiredParser<Type, Input extends { required: boolean }>(
|
||||
return parser.nullable() as any
|
||||
}
|
||||
|
||||
export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
export class Value<
|
||||
Type extends StaticValidatedAs,
|
||||
StaticValidatedAs = Type,
|
||||
OuterType = unknown,
|
||||
> {
|
||||
protected constructor(
|
||||
public build: LazyBuild<{
|
||||
spec: ValueSpec
|
||||
validator: Parser<unknown, Type>
|
||||
}>,
|
||||
public build: LazyBuild<
|
||||
{
|
||||
spec: ValueSpec
|
||||
validator: Parser<unknown, Type>
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
public readonly validator: Parser<unknown, StaticValidatedAs>,
|
||||
) {}
|
||||
public _TYPE: Type = null as any as Type
|
||||
@@ -102,17 +109,20 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
validator,
|
||||
)
|
||||
}
|
||||
static dynamicToggle(
|
||||
a: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: boolean
|
||||
disabled?: false | string
|
||||
}>,
|
||||
static dynamicToggle<OuterType = unknown>(
|
||||
a: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: boolean
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
const validator = boolean
|
||||
return new Value<boolean>(
|
||||
return new Value<boolean, boolean, OuterType>(
|
||||
async (options) => ({
|
||||
spec: {
|
||||
description: null,
|
||||
@@ -225,24 +235,27 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
validator,
|
||||
)
|
||||
}
|
||||
static dynamicText<Required extends boolean>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: DefaultString | null
|
||||
required: Required
|
||||
masked?: boolean
|
||||
placeholder?: string | null
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ValueSpecText['inputmode']
|
||||
disabled?: string | false
|
||||
generate?: null | RandomString
|
||||
}>,
|
||||
static dynamicText<Required extends boolean, OuterType = unknown>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: DefaultString | null
|
||||
required: Required
|
||||
masked?: boolean
|
||||
placeholder?: string | null
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ValueSpecText['inputmode']
|
||||
disabled?: string | false
|
||||
generate?: null | RandomString
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<AsRequired<string, Required>, string | null>(
|
||||
return new Value<AsRequired<string, Required>, string | null, OuterType>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
@@ -342,23 +355,26 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return { spec: built, validator }
|
||||
}, validator)
|
||||
}
|
||||
static dynamicTextarea<Required extends boolean>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
minRows?: number
|
||||
maxRows?: number
|
||||
placeholder?: string | null
|
||||
disabled?: false | string
|
||||
}>,
|
||||
static dynamicTextarea<Required extends boolean, OuterType = unknown>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
minRows?: number
|
||||
maxRows?: number
|
||||
placeholder?: string | null
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<AsRequired<string, Required>, string | null>(
|
||||
return new Value<AsRequired<string, Required>, string | null, OuterType>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
@@ -461,23 +477,26 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
validator,
|
||||
)
|
||||
}
|
||||
static dynamicNumber<Required extends boolean>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: number | null
|
||||
required: Required
|
||||
min?: number | null
|
||||
max?: number | null
|
||||
step?: number | null
|
||||
integer: boolean
|
||||
units?: string | null
|
||||
placeholder?: string | null
|
||||
disabled?: false | string
|
||||
}>,
|
||||
static dynamicNumber<Required extends boolean, OuterType = unknown>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: number | null
|
||||
required: Required
|
||||
min?: number | null
|
||||
max?: number | null
|
||||
step?: number | null
|
||||
integer: boolean
|
||||
units?: string | null
|
||||
placeholder?: string | null
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<AsRequired<number, Required>, number | null>(
|
||||
return new Value<AsRequired<number, Required>, number | null, OuterType>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
@@ -553,17 +572,20 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
)
|
||||
}
|
||||
|
||||
static dynamicColor<Required extends boolean>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
disabled?: false | string
|
||||
}>,
|
||||
static dynamicColor<Required extends boolean, OuterType = unknown>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<AsRequired<string, Required>, string | null>(
|
||||
return new Value<AsRequired<string, Required>, string | null, OuterType>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
@@ -647,20 +669,23 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
validator,
|
||||
)
|
||||
}
|
||||
static dynamicDatetime<Required extends boolean>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
inputmode?: ValueSpecDatetime['inputmode']
|
||||
min?: string | null
|
||||
max?: string | null
|
||||
disabled?: false | string
|
||||
}>,
|
||||
static dynamicDatetime<Required extends boolean, OuterType = unknown>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
inputmode?: ValueSpecDatetime['inputmode']
|
||||
min?: string | null
|
||||
max?: string | null
|
||||
disabled?: false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<AsRequired<string, Required>, string | null>(
|
||||
return new Value<AsRequired<string, Required>, string | null, OuterType>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
@@ -750,34 +775,43 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
validator,
|
||||
)
|
||||
}
|
||||
static dynamicSelect<Values extends Record<string, string>>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string
|
||||
values: Values
|
||||
disabled?: false | string | string[]
|
||||
}>,
|
||||
static dynamicSelect<
|
||||
Values extends Record<string, string>,
|
||||
OuterType = unknown,
|
||||
>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string
|
||||
values: Values
|
||||
disabled?: false | string | string[]
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<keyof Values & string, string>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: 'select' as const,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
},
|
||||
validator: anyOf(
|
||||
...Object.keys(a.values).map((x: keyof Values & string) =>
|
||||
literal(x),
|
||||
return new Value<keyof Values & string, keyof Values & string, OuterType>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: 'select' as const,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
},
|
||||
validator: anyOf(
|
||||
...Object.keys(a.values).map((x: keyof Values & string) =>
|
||||
literal(x),
|
||||
),
|
||||
),
|
||||
),
|
||||
}
|
||||
}, string)
|
||||
}
|
||||
},
|
||||
string,
|
||||
)
|
||||
}
|
||||
/**
|
||||
* @description Displays a select modal with checkboxes, allowing for multiple selections.
|
||||
@@ -851,19 +885,29 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
validator,
|
||||
)
|
||||
}
|
||||
static dynamicMultiselect<Values extends Record<string, string>>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string[]
|
||||
values: Values
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
disabled?: false | string | string[]
|
||||
}>,
|
||||
static dynamicMultiselect<
|
||||
Values extends Record<string, string>,
|
||||
OuterType = unknown,
|
||||
>(
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
default: string[]
|
||||
values: Values
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
disabled?: false | string | string[]
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<(keyof Values & string)[], string[]>(async (options) => {
|
||||
return new Value<
|
||||
(keyof Values & string)[],
|
||||
(keyof Values & string)[],
|
||||
OuterType
|
||||
>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
@@ -948,30 +992,34 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
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),
|
||||
}
|
||||
static dynamicFile<Required extends boolean, OuterType = unknown>(
|
||||
a: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
extensions: string[]
|
||||
required: Required
|
||||
},
|
||||
fileInfoParser.nullable(),
|
||||
)
|
||||
OuterType
|
||||
>,
|
||||
) {
|
||||
return new Value<
|
||||
AsRequired<FileInfo, Required>,
|
||||
FileInfo | null,
|
||||
OuterType
|
||||
>(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.
|
||||
@@ -1053,37 +1101,46 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
spec: InputSpec<any>
|
||||
}
|
||||
},
|
||||
OuterType = unknown,
|
||||
>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
}>,
|
||||
): Value<UnionRes<VariantValues>, unknown>
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
): Value<UnionRes<VariantValues>, UnionRes<VariantValues>, OuterType>
|
||||
static dynamicUnion<
|
||||
VariantValues extends StaticVariantValues,
|
||||
StaticVariantValues extends {
|
||||
[K in string]: {
|
||||
name: string
|
||||
spec: InputSpec<any, any>
|
||||
}
|
||||
},
|
||||
VariantValues extends StaticVariantValues,
|
||||
OuterType = unknown,
|
||||
>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
}>,
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
validator: Parser<unknown, UnionResStaticValidatedAs<StaticVariantValues>>,
|
||||
): Value<
|
||||
UnionRes<VariantValues>,
|
||||
UnionResStaticValidatedAs<StaticVariantValues>
|
||||
UnionResStaticValidatedAs<StaticVariantValues>,
|
||||
OuterType
|
||||
>
|
||||
static dynamicUnion<
|
||||
VariantValues extends {
|
||||
@@ -1092,35 +1149,40 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
spec: InputSpec<any>
|
||||
}
|
||||
},
|
||||
OuterType = unknown,
|
||||
>(
|
||||
getA: LazyBuild<{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
}>,
|
||||
getA: LazyBuild<
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
variants: Variants<VariantValues>
|
||||
default: keyof VariantValues & string
|
||||
disabled: string[] | false | string
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
validator: Parser<unknown, unknown> = any,
|
||||
) {
|
||||
return new Value<UnionRes<VariantValues>, typeof validator._TYPE>(
|
||||
async (options) => {
|
||||
const newValues = await getA(options)
|
||||
const built = await newValues.variants.build(options as any)
|
||||
return {
|
||||
spec: {
|
||||
type: 'union' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...newValues,
|
||||
variants: built.spec,
|
||||
immutable: false,
|
||||
},
|
||||
validator: built.validator,
|
||||
}
|
||||
},
|
||||
validator,
|
||||
)
|
||||
return new Value<
|
||||
UnionRes<VariantValues>,
|
||||
typeof validator._TYPE,
|
||||
OuterType
|
||||
>(async (options) => {
|
||||
const newValues = await getA(options)
|
||||
const built = await newValues.variants.build(options as any)
|
||||
return {
|
||||
spec: {
|
||||
type: 'union' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...newValues,
|
||||
variants: built.spec,
|
||||
immutable: false,
|
||||
},
|
||||
validator: built.validator,
|
||||
}
|
||||
}, validator)
|
||||
}
|
||||
/**
|
||||
* @description Presents an interface to add/remove/edit items in a list.
|
||||
@@ -1196,7 +1258,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
hiddenExample: Value.hidden(),
|
||||
* ```
|
||||
*/
|
||||
static hidden<T>(): Value<T, unknown>
|
||||
static hidden<T>(): Value<T>
|
||||
static hidden<T>(parser: Parser<unknown, T>): Value<T>
|
||||
static hidden<T>(parser: Parser<unknown, T> = any) {
|
||||
return new Value<T, typeof parser._TYPE>(async () => {
|
||||
@@ -1216,8 +1278,10 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
hiddenExample: Value.hidden(),
|
||||
* ```
|
||||
*/
|
||||
static dynamicHidden<T>(getParser: LazyBuild<Parser<unknown, T>>) {
|
||||
return new Value<T, unknown>(async (options) => {
|
||||
static dynamicHidden<T, OuterType = unknown>(
|
||||
getParser: LazyBuild<Parser<unknown, T>, OuterType>,
|
||||
) {
|
||||
return new Value<T, T, OuterType>(async (options) => {
|
||||
const validator = await getParser(options)
|
||||
return {
|
||||
spec: {
|
||||
@@ -1228,9 +1292,9 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
}, any)
|
||||
}
|
||||
|
||||
map<U>(fn: (value: StaticValidatedAs) => U): Value<U> {
|
||||
return new Value(async (effects) => {
|
||||
const built = await this.build(effects)
|
||||
map<U>(fn: (value: StaticValidatedAs) => U): Value<U, U, OuterType> {
|
||||
return new Value<U, U, OuterType>(async (options) => {
|
||||
const built = await this.build(options)
|
||||
return {
|
||||
spec: built.spec,
|
||||
validator: built.validator.map(fn),
|
||||
|
||||
@@ -103,12 +103,16 @@ export class Variants<
|
||||
spec: InputSpec<any, any>
|
||||
}
|
||||
},
|
||||
OuterType = unknown,
|
||||
> {
|
||||
private constructor(
|
||||
public build: LazyBuild<{
|
||||
spec: ValueSpecUnion['variants']
|
||||
validator: Parser<unknown, UnionRes<VariantValues>>
|
||||
}>,
|
||||
public build: LazyBuild<
|
||||
{
|
||||
spec: ValueSpecUnion['variants']
|
||||
validator: Parser<unknown, UnionRes<VariantValues>>
|
||||
},
|
||||
OuterType
|
||||
>,
|
||||
public readonly validator: Parser<
|
||||
unknown,
|
||||
UnionResStaticValidatedAs<VariantValues>
|
||||
|
||||
@@ -13,6 +13,7 @@ export type Run<A extends Record<string, any>> = (options: {
|
||||
}) => Promise<(T.ActionResult & { version: '1' }) | null | void | undefined>
|
||||
export type GetInput<A extends Record<string, any>> = (options: {
|
||||
effects: T.Effects
|
||||
prefill: T.DeepPartial<A> | null
|
||||
}) => Promise<null | void | undefined | T.DeepPartial<A>>
|
||||
|
||||
export type MaybeFn<T> = T | ((options: { effects: T.Effects }) => Promise<T>)
|
||||
@@ -104,7 +105,10 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
await options.effects.action.export({ id: this.id, metadata })
|
||||
return metadata
|
||||
}
|
||||
async getInput(options: { effects: T.Effects }): Promise<T.ActionInput> {
|
||||
async getInput(options: {
|
||||
effects: T.Effects
|
||||
prefill: T.DeepPartial<Type> | null
|
||||
}): Promise<T.ActionInput> {
|
||||
let spec = {}
|
||||
if (this.inputSpec) {
|
||||
const built = await this.inputSpec.build(options)
|
||||
|
||||
@@ -2,4 +2,8 @@
|
||||
import type { ActionId } from './ActionId'
|
||||
import type { PackageId } from './PackageId'
|
||||
|
||||
export type GetActionInputParams = { packageId?: PackageId; actionId: ActionId }
|
||||
export type GetActionInputParams = {
|
||||
packageId?: PackageId
|
||||
actionId: ActionId
|
||||
prefill: Record<string, unknown> | null
|
||||
}
|
||||
|
||||
4
sdk/package/package-lock.json
generated
4
sdk/package/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.49",
|
||||
"version": "0.4.0-beta.50",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.49",
|
||||
"version": "0.4.0-beta.50",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@iarna/toml": "^3.0.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@start9labs/start-sdk",
|
||||
"version": "0.4.0-beta.49",
|
||||
"version": "0.4.0-beta.50",
|
||||
"description": "Software development kit to facilitate packaging services for StartOS",
|
||||
"main": "./package/lib/index.js",
|
||||
"types": "./package/lib/index.d.ts",
|
||||
|
||||
@@ -148,6 +148,7 @@ export class ActionInputModal {
|
||||
this.api.getActionInput({
|
||||
packageId: this.pkgInfo.id,
|
||||
actionId: this.actionId,
|
||||
prefill: this.context.data.prefill ?? null,
|
||||
}),
|
||||
).pipe(
|
||||
map(res => {
|
||||
|
||||
Reference in New Issue
Block a user