feat(core): rework form when conditions (#35115)
This commit is contained in:
@@ -2453,7 +2453,11 @@ export type FormListRequestsOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -2473,7 +2477,11 @@ export type FormListRequestsOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2484,7 +2492,11 @@ export type FormListRequestsOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2495,7 +2507,11 @@ export type FormListRequestsOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -2504,7 +2520,11 @@ export type FormListRequestsOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -2545,7 +2565,11 @@ export type FormListOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -2565,7 +2589,11 @@ export type FormListOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2576,7 +2604,11 @@ export type FormListOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2587,7 +2619,11 @@ export type FormListOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -2596,7 +2632,11 @@ export type FormListOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -2634,7 +2674,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -2654,7 +2698,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2665,7 +2713,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2676,7 +2728,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -2685,7 +2741,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -2711,7 +2771,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -2731,7 +2795,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2742,7 +2810,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2753,7 +2825,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -2762,7 +2838,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -2788,7 +2868,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -2808,7 +2892,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2819,7 +2907,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2830,7 +2922,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -2839,7 +2935,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -2865,7 +2965,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -2885,7 +2989,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2896,7 +3004,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2907,7 +3019,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -2916,7 +3032,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -2942,7 +3062,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -2962,7 +3086,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2973,7 +3101,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -2984,7 +3116,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -2993,7 +3129,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -3019,7 +3159,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -3039,7 +3183,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3050,7 +3198,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3061,7 +3213,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -3070,7 +3226,11 @@ export type FormCreateInput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -3101,7 +3261,11 @@ export type FormCreateOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -3121,7 +3285,11 @@ export type FormCreateOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3132,7 +3300,11 @@ export type FormCreateOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3143,7 +3315,11 @@ export type FormCreateOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -3152,7 +3328,11 @@ export type FormCreateOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -3195,7 +3375,11 @@ export type FormGetOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -3215,7 +3399,11 @@ export type FormGetOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3226,7 +3414,11 @@ export type FormGetOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly minimum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
readonly maximum?: number | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3237,7 +3429,11 @@ export type FormGetOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -3246,7 +3442,11 @@ export type FormGetOutput = {
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
@@ -4933,7 +5133,11 @@ export type EventSubscribeOutput =
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | boolean
|
||||||
|
}>
|
||||||
readonly type: "string"
|
readonly type: "string"
|
||||||
readonly format?: "email" | "uri" | "date" | "date-time"
|
readonly format?: "email" | "uri" | "date" | "date-time"
|
||||||
readonly minLength?: number
|
readonly minLength?: number
|
||||||
@@ -4953,7 +5157,11 @@ export type EventSubscribeOutput =
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | boolean
|
||||||
|
}>
|
||||||
readonly type: "number"
|
readonly type: "number"
|
||||||
readonly minimum?: number
|
readonly minimum?: number
|
||||||
readonly maximum?: number
|
readonly maximum?: number
|
||||||
@@ -4964,7 +5172,11 @@ export type EventSubscribeOutput =
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | boolean
|
||||||
|
}>
|
||||||
readonly type: "integer"
|
readonly type: "integer"
|
||||||
readonly minimum?: number
|
readonly minimum?: number
|
||||||
readonly maximum?: number
|
readonly maximum?: number
|
||||||
@@ -4975,7 +5187,11 @@ export type EventSubscribeOutput =
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | boolean
|
||||||
|
}>
|
||||||
readonly type: "boolean"
|
readonly type: "boolean"
|
||||||
readonly default?: boolean
|
readonly default?: boolean
|
||||||
}
|
}
|
||||||
@@ -4984,7 +5200,11 @@ export type EventSubscribeOutput =
|
|||||||
readonly title?: string
|
readonly title?: string
|
||||||
readonly description?: string
|
readonly description?: string
|
||||||
readonly required?: boolean
|
readonly required?: boolean
|
||||||
readonly when?: { readonly key: string; readonly op: "eq" | "neq"; readonly value: string }
|
readonly when?: ReadonlyArray<{
|
||||||
|
readonly key: string
|
||||||
|
readonly op: "eq" | "neq"
|
||||||
|
readonly value: string | number | boolean
|
||||||
|
}>
|
||||||
readonly type: "multiselect"
|
readonly type: "multiselect"
|
||||||
readonly options: ReadonlyArray<{
|
readonly options: ReadonlyArray<{
|
||||||
readonly value: string
|
readonly value: string
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ export type Info = typeof Info.Type
|
|||||||
export const Field = Form.Field
|
export const Field = Form.Field
|
||||||
export type Field = Form.Field
|
export type Field = Form.Field
|
||||||
|
|
||||||
|
export const When = Form.When
|
||||||
|
export type When = Form.When
|
||||||
|
|
||||||
export const State = Form.State
|
export const State = Form.State
|
||||||
export type State = typeof State.Type
|
export type State = typeof State.Type
|
||||||
|
|
||||||
@@ -56,6 +59,10 @@ export class InvalidAnswerError extends Schema.TaggedErrorClass<InvalidAnswerErr
|
|||||||
message: Schema.String,
|
message: Schema.String,
|
||||||
}) {}
|
}) {}
|
||||||
|
|
||||||
|
export class InvalidFormError extends Schema.TaggedErrorClass<InvalidFormError>()("Form.InvalidFormError", {
|
||||||
|
message: Schema.String,
|
||||||
|
}) {}
|
||||||
|
|
||||||
export type CreateInput =
|
export type CreateInput =
|
||||||
| (Omit<Form.FormInfo, "id"> & { readonly id?: ID })
|
| (Omit<Form.FormInfo, "id"> & { readonly id?: ID })
|
||||||
| (Omit<Form.UrlInfo, "id"> & { readonly id?: ID })
|
| (Omit<Form.UrlInfo, "id"> & { readonly id?: ID })
|
||||||
@@ -70,8 +77,8 @@ export interface ListInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly create: (input: CreateInput) => Effect.Effect<Info, AlreadyExistsError>
|
readonly create: (input: CreateInput) => Effect.Effect<Info, AlreadyExistsError | InvalidFormError>
|
||||||
readonly ask: (input: CreateInput) => Effect.Effect<State, AlreadyExistsError>
|
readonly ask: (input: CreateInput) => Effect.Effect<State, AlreadyExistsError | InvalidFormError>
|
||||||
readonly get: (id: ID) => Effect.Effect<Info, NotFoundError>
|
readonly get: (id: ID) => Effect.Effect<Info, NotFoundError>
|
||||||
readonly list: (input?: ListInput) => Effect.Effect<ReadonlyArray<Info>>
|
readonly list: (input?: ListInput) => Effect.Effect<ReadonlyArray<Info>>
|
||||||
readonly state: (id: ID) => Effect.Effect<State, NotFoundError>
|
readonly state: (id: ID) => Effect.Effect<State, NotFoundError>
|
||||||
@@ -113,6 +120,10 @@ export const layer = Layer.effect(
|
|||||||
const id = input.id ?? ID.create()
|
const id = input.id ?? ID.create()
|
||||||
const existing = yield* Cache.getSuccess(forms, id)
|
const existing = yield* Cache.getSuccess(forms, id)
|
||||||
if (Option.isSome(existing)) return yield* new AlreadyExistsError({ id })
|
if (Option.isSome(existing)) return yield* new AlreadyExistsError({ id })
|
||||||
|
if (input.mode === "form") {
|
||||||
|
const invalid = validateFields(input.fields)
|
||||||
|
if (invalid) return yield* new InvalidFormError({ message: invalid })
|
||||||
|
}
|
||||||
const base = {
|
const base = {
|
||||||
id,
|
id,
|
||||||
sessionID: input.sessionID,
|
sessionID: input.sessionID,
|
||||||
@@ -218,10 +229,12 @@ function validateAnswer(form: Info, answer: Answer) {
|
|||||||
}
|
}
|
||||||
for (const field of form.fields) {
|
for (const field of form.fields) {
|
||||||
const value = answer[field.key]
|
const value = answer[field.key]
|
||||||
|
const active = isActive(field, answer)
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
if (field.required && isActive(field, answer)) return `Missing required form field: ${field.key}`
|
if (field.required && active) return `Missing required form field: ${field.key}`
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
if (!active) return `Form field is not active: ${field.key}`
|
||||||
const invalid = validateField(field, value)
|
const invalid = validateField(field, value)
|
||||||
if (invalid) return invalid
|
if (invalid) return invalid
|
||||||
}
|
}
|
||||||
@@ -229,9 +242,50 @@ function validateAnswer(form: Info, answer: Answer) {
|
|||||||
|
|
||||||
function isActive(field: Form.Field, answer: Answer) {
|
function isActive(field: Form.Field, answer: Answer) {
|
||||||
if (!field.when) return true
|
if (!field.when) return true
|
||||||
const value = answer[field.when.key]
|
return field.when.every((when) => matches(when, answer[when.key]))
|
||||||
if (field.when.op === "eq") return value === field.when.value
|
}
|
||||||
return value !== field.when.value
|
|
||||||
|
// An unanswered referenced field makes the condition false for both ops. Combined with inactive
|
||||||
|
// fields being unanswerable, this cascades: hiding a field falsifies every condition referencing it.
|
||||||
|
function matches(when: Form.When, value: Form.Value | undefined) {
|
||||||
|
if (value === undefined) return false
|
||||||
|
const hit = Array.isArray(value) ? value.some((item) => item === when.value) : value === when.value
|
||||||
|
return when.op === "eq" ? hit : !hit
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create-time validation of `when` references: each condition must point at an earlier field,
|
||||||
|
// carry a value matching that field's type, and use a declared option when the field's options
|
||||||
|
// are closed. Rejecting these at creation surfaces authoring mistakes to the caller instead of
|
||||||
|
// silently never matching.
|
||||||
|
function validateFields(fields: ReadonlyArray<Form.Field>) {
|
||||||
|
const earlier = new Map<string, Form.Field>()
|
||||||
|
for (const field of fields) {
|
||||||
|
if (earlier.has(field.key)) return `Duplicate form field key: ${field.key}`
|
||||||
|
for (const when of field.when ?? []) {
|
||||||
|
const target = earlier.get(when.key)
|
||||||
|
if (!target) return `Form field condition must reference an earlier field: ${field.key} -> ${when.key}`
|
||||||
|
const invalid = validateWhen(when, target)
|
||||||
|
if (invalid) return `${invalid}: ${field.key} -> ${when.key}`
|
||||||
|
}
|
||||||
|
earlier.set(field.key, field)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function validateWhen(when: Form.When, target: Form.Field) {
|
||||||
|
if (target.type === "boolean") {
|
||||||
|
if (typeof when.value !== "boolean") return "Form field condition value must be a boolean"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (target.type === "number" || target.type === "integer") {
|
||||||
|
if (typeof when.value !== "number") return "Form field condition value must be a number"
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// string and multiselect targets both compare against string values
|
||||||
|
if (typeof when.value !== "string") return "Form field condition value must be a string"
|
||||||
|
const closed = target.type === "multiselect" ? !target.custom : target.options !== undefined && !target.custom
|
||||||
|
if (closed && !target.options?.some((option) => option.value === when.value)) {
|
||||||
|
return "Form field condition value must be one of the field's options"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateField(field: Form.Field, value: Form.Value): string | undefined {
|
function validateField(field: Form.Field, value: Form.Value): string | undefined {
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
|
|||||||
import { UnauthorizedError, type OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"
|
import { UnauthorizedError, type OAuthClientProvider } from "@modelcontextprotocol/sdk/client/auth.js"
|
||||||
import {
|
import {
|
||||||
CallToolResultSchema,
|
CallToolResultSchema,
|
||||||
|
ElicitationCompleteNotificationSchema,
|
||||||
|
ElicitRequestSchema,
|
||||||
GetPromptResultSchema,
|
GetPromptResultSchema,
|
||||||
|
type ElicitRequestFormParams,
|
||||||
|
type ElicitRequestParams,
|
||||||
|
type ElicitRequestURLParams,
|
||||||
|
type ElicitResult,
|
||||||
ListPromptsResultSchema,
|
ListPromptsResultSchema,
|
||||||
ListRootsRequestSchema,
|
ListRootsRequestSchema,
|
||||||
ListToolsResultSchema,
|
ListToolsResultSchema,
|
||||||
@@ -82,6 +88,22 @@ export interface CallToolResult {
|
|||||||
readonly content: ReadonlyArray<CallToolContent>
|
readonly content: ReadonlyArray<CallToolContent>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ElicitationFormParams = ElicitRequestFormParams
|
||||||
|
export type ElicitationParams = ElicitRequestParams
|
||||||
|
export type ElicitationResult = ElicitResult
|
||||||
|
|
||||||
|
export interface ElicitationHandler {
|
||||||
|
readonly create: (input: {
|
||||||
|
readonly server: string
|
||||||
|
readonly params: ElicitationParams
|
||||||
|
readonly signal: AbortSignal
|
||||||
|
}) => Effect.Effect<ElicitationResult, Error>
|
||||||
|
readonly complete: (input: {
|
||||||
|
readonly server: string
|
||||||
|
readonly elicitationID: ElicitRequestURLParams["elicitationId"]
|
||||||
|
}) => Effect.Effect<void>
|
||||||
|
}
|
||||||
|
|
||||||
export interface LogMessage {
|
export interface LogMessage {
|
||||||
readonly level: LoggingMessageNotification["params"]["level"]
|
readonly level: LoggingMessageNotification["params"]["level"]
|
||||||
readonly logger?: LoggingMessageNotification["params"]["logger"]
|
readonly logger?: LoggingMessageNotification["params"]["logger"]
|
||||||
@@ -123,6 +145,7 @@ export const connect = Effect.fnUntraced(function* (
|
|||||||
// Only consumed by the remote transport; stdio servers have no auth concept. A provider with no
|
// Only consumed by the remote transport; stdio servers have no auth concept. A provider with no
|
||||||
// stored token (and a no-op redirect) surfaces an UnauthorizedError, which we map to needs_auth.
|
// stored token (and a no-op redirect) surfaces an UnauthorizedError, which we map to needs_auth.
|
||||||
authProvider?: OAuthClientProvider,
|
authProvider?: OAuthClientProvider,
|
||||||
|
elicitation?: ElicitationHandler,
|
||||||
) {
|
) {
|
||||||
const transport: Transport = yield* Effect.gen(function* () {
|
const transport: Transport = yield* Effect.gen(function* () {
|
||||||
if (config.type === "local") {
|
if (config.type === "local") {
|
||||||
@@ -149,6 +172,7 @@ export const connect = Effect.fnUntraced(function* (
|
|||||||
{ name: "opencode", version: InstallationVersion },
|
{ name: "opencode", version: InstallationVersion },
|
||||||
{
|
{
|
||||||
capabilities: {
|
capabilities: {
|
||||||
|
...(elicitation ? { elicitation: { form: { applyDefaults: true }, url: {} } } : {}),
|
||||||
// https://github.com/anomalyco/opencode/issues/2308
|
// https://github.com/anomalyco/opencode/issues/2308
|
||||||
roots: {},
|
roots: {},
|
||||||
},
|
},
|
||||||
@@ -157,6 +181,14 @@ export const connect = Effect.fnUntraced(function* (
|
|||||||
client.setRequestHandler(ListRootsRequestSchema, () =>
|
client.setRequestHandler(ListRootsRequestSchema, () =>
|
||||||
Promise.resolve({ roots: [{ uri: pathToFileURL(directory).href }] }),
|
Promise.resolve({ roots: [{ uri: pathToFileURL(directory).href }] }),
|
||||||
)
|
)
|
||||||
|
if (elicitation) {
|
||||||
|
client.setRequestHandler(ElicitRequestSchema, (request, extra) =>
|
||||||
|
Effect.runPromise(elicitation.create({ server, params: request.params, signal: extra.signal })),
|
||||||
|
)
|
||||||
|
client.setNotificationHandler(ElicitationCompleteNotificationSchema, (notification) =>
|
||||||
|
Effect.runPromise(elicitation.complete({ server, elicitationID: notification.params.elicitationId })),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const exit = yield* Effect.tryPromise({
|
const exit = yield* Effect.tryPromise({
|
||||||
try: (signal) => client.connect(transport, { timeout: config.timeout?.startup ?? DEFAULT_STARTUP_TIMEOUT, signal }),
|
try: (signal) => client.connect(transport, { timeout: config.timeout?.startup ?? DEFAULT_STARTUP_TIMEOUT, signal }),
|
||||||
|
|||||||
@@ -10,9 +10,11 @@ import { Config } from "../config"
|
|||||||
import { ConfigMCP } from "../config/mcp"
|
import { ConfigMCP } from "../config/mcp"
|
||||||
import { Credential } from "../credential"
|
import { Credential } from "../credential"
|
||||||
import { EventV2 } from "../event"
|
import { EventV2 } from "../event"
|
||||||
|
import { Form } from "../form"
|
||||||
import { Integration } from "../integration"
|
import { Integration } from "../integration"
|
||||||
import { IntegrationConnection } from "../integration/connection"
|
import { IntegrationConnection } from "../integration/connection"
|
||||||
import { Location } from "../location"
|
import { Location } from "../location"
|
||||||
|
import { waitForAbort } from "../process"
|
||||||
import { MCPClient } from "./client"
|
import { MCPClient } from "./client"
|
||||||
import { MCPOAuth } from "./oauth"
|
import { MCPOAuth } from "./oauth"
|
||||||
|
|
||||||
@@ -145,6 +147,10 @@ type ServerEntry = {
|
|||||||
integrationID?: Integration.ID
|
integrationID?: Integration.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MCP elicitations are Location-scoped, not Session-scoped: the server cannot attribute them to a
|
||||||
|
// persisted session row, so their forms are owned by this opaque sentinel session identifier.
|
||||||
|
const GLOBAL_ELICITATION_SESSION_ID = "global"
|
||||||
|
|
||||||
export interface Interface {
|
export interface Interface {
|
||||||
readonly servers: () => Effect.Effect<ServerInfo[]>
|
readonly servers: () => Effect.Effect<ServerInfo[]>
|
||||||
readonly tools: () => Effect.Effect<Tool[]>
|
readonly tools: () => Effect.Effect<Tool[]>
|
||||||
@@ -175,6 +181,7 @@ export const layer = Layer.effect(
|
|||||||
const config = yield* Config.Service
|
const config = yield* Config.Service
|
||||||
const location = yield* Location.Service
|
const location = yield* Location.Service
|
||||||
const events = yield* EventV2.Service
|
const events = yield* EventV2.Service
|
||||||
|
const forms = yield* Form.Service
|
||||||
const integration = yield* Integration.Service
|
const integration = yield* Integration.Service
|
||||||
const credentials = yield* Credential.Service
|
const credentials = yield* Credential.Service
|
||||||
const root = yield* Scope.make()
|
const root = yield* Scope.make()
|
||||||
@@ -189,6 +196,7 @@ export const layer = Layer.effect(
|
|||||||
)
|
)
|
||||||
// Later config files win for duplicate server names; per-server timeout overrides globals.
|
// Later config files win for duplicate server names; per-server timeout overrides globals.
|
||||||
const runtime = new Map<ServerName, ServerEntry>()
|
const runtime = new Map<ServerName, ServerEntry>()
|
||||||
|
const urlElicitations = new Map<string, Form.ID>()
|
||||||
for (const entry of documents) {
|
for (const entry of documents) {
|
||||||
for (const [name, server] of Object.entries(entry.info.mcp?.servers ?? {})) {
|
for (const [name, server] of Object.entries(entry.info.mcp?.servers ?? {})) {
|
||||||
runtime.set(ServerName.make(name), {
|
runtime.set(ServerName.make(name), {
|
||||||
@@ -308,6 +316,76 @@ export const layer = Layer.effect(
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const elicitation = {
|
||||||
|
create: (input: {
|
||||||
|
readonly server: string
|
||||||
|
readonly params: MCPClient.ElicitationParams
|
||||||
|
readonly signal: AbortSignal
|
||||||
|
}) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
if (input.params.mode === "url") {
|
||||||
|
const formID = Form.ID.create()
|
||||||
|
const key = input.server + "\u0000" + input.params.elicitationId
|
||||||
|
urlElicitations.set(key, formID)
|
||||||
|
return yield* forms
|
||||||
|
.ask({
|
||||||
|
id: formID,
|
||||||
|
sessionID: GLOBAL_ELICITATION_SESSION_ID,
|
||||||
|
title: `${input.server} is requesting input`,
|
||||||
|
metadata: {
|
||||||
|
kind: "mcp-elicitation",
|
||||||
|
server: input.server,
|
||||||
|
elicitationID: input.params.elicitationId,
|
||||||
|
message: input.params.message,
|
||||||
|
},
|
||||||
|
mode: "url",
|
||||||
|
url: input.params.url,
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
Effect.raceFirst(waitForAbort(input.signal)),
|
||||||
|
Effect.ensuring(Effect.sync(() => urlElicitations.delete(key))),
|
||||||
|
Effect.map(
|
||||||
|
(state): MCPClient.ElicitationResult => ({
|
||||||
|
action: state.status === "answered" ? "accept" : "cancel",
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const params = input.params
|
||||||
|
return yield* forms
|
||||||
|
.ask({
|
||||||
|
sessionID: GLOBAL_ELICITATION_SESSION_ID,
|
||||||
|
title: `${input.server} is requesting input`,
|
||||||
|
metadata: { kind: "mcp-elicitation", server: input.server, message: params.message },
|
||||||
|
mode: "form",
|
||||||
|
fields: Object.entries(params.requestedSchema.properties).map(([key, property]) =>
|
||||||
|
toElicitationField(key, property, params.requestedSchema.required?.includes(key) === true),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
.pipe(
|
||||||
|
Effect.raceFirst(waitForAbort(input.signal)),
|
||||||
|
Effect.map((state): MCPClient.ElicitationResult => {
|
||||||
|
if (state.status !== "answered") return { action: "cancel" }
|
||||||
|
return {
|
||||||
|
action: "accept",
|
||||||
|
content: Object.fromEntries(
|
||||||
|
Object.entries(state.answer).map(
|
||||||
|
([key, value]): [string, NonNullable<MCPClient.ElicitationResult["content"]>[string]] =>
|
||||||
|
typeof value === "object" ? [key, Array.from(value)] : [key, value],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
complete: (input: { readonly server: string; readonly elicitationID: string }) =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const formID = urlElicitations.get(input.server + "\u0000" + input.elicitationID)
|
||||||
|
if (!formID) return
|
||||||
|
yield* forms.reply({ id: formID, answer: {} }).pipe(Effect.ignore)
|
||||||
|
}),
|
||||||
|
} satisfies MCPClient.ElicitationHandler
|
||||||
|
|
||||||
const toTool = (server: ServerName, def: MCPClient.ToolDefinition) =>
|
const toTool = (server: ServerName, def: MCPClient.ToolDefinition) =>
|
||||||
new Tool({ server, name: def.name, description: def.description, inputSchema: def.inputSchema })
|
new Tool({ server, name: def.name, description: def.description, inputSchema: def.inputSchema })
|
||||||
|
|
||||||
@@ -396,7 +474,7 @@ export const layer = Layer.effect(
|
|||||||
const authProvider = yield* connectProvider(entry)
|
const authProvider = yield* connectProvider(entry)
|
||||||
// List tools as part of connect so a failure here marks the server failed rather than
|
// List tools as part of connect so a failure here marks the server failed rather than
|
||||||
// leaving it connected with a silently empty tool list and no path to recover.
|
// leaving it connected with a silently empty tool list and no path to recover.
|
||||||
const result = yield* MCPClient.connect(name, entry.config, location.directory, authProvider).pipe(
|
const result = yield* MCPClient.connect(name, entry.config, location.directory, authProvider, elicitation).pipe(
|
||||||
Effect.flatMap((connection) => connection.tools().pipe(Effect.map((tools) => ({ connection, tools })))),
|
Effect.flatMap((connection) => connection.tools().pipe(Effect.map((tools) => ({ connection, tools })))),
|
||||||
Scope.provide(scope),
|
Scope.provide(scope),
|
||||||
Effect.exit,
|
Effect.exit,
|
||||||
@@ -561,5 +639,69 @@ export const layer = Layer.effect(
|
|||||||
export const node = makeLocationNode({
|
export const node = makeLocationNode({
|
||||||
service: Service,
|
service: Service,
|
||||||
layer,
|
layer,
|
||||||
deps: [Config.node, Location.node, EventV2.node, Integration.node, Credential.node],
|
deps: [Config.node, Location.node, EventV2.node, Form.node, Integration.node, Credential.node],
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// Schema `optional` strips undefined-valued properties on encode, so fields can assign
|
||||||
|
// optional properties directly instead of conditionally spreading them.
|
||||||
|
function toElicitationField(key: string, property: ElicitationProperty, required: boolean): Form.Field {
|
||||||
|
// Some servers emit machine titles like "string with format email"; prefer description/key over those.
|
||||||
|
const machineTitle = /^(boolean|string|number|integer|array|object)(\s+with\b.*|\s+in\b.*)?$/i
|
||||||
|
const title =
|
||||||
|
property.title && !machineTitle.test(property.title.trim()) ? property.title : (property.description ?? key)
|
||||||
|
const base = {
|
||||||
|
key,
|
||||||
|
title,
|
||||||
|
description: property.description === title ? undefined : property.description,
|
||||||
|
required: required || undefined,
|
||||||
|
}
|
||||||
|
switch (property.type) {
|
||||||
|
case "boolean":
|
||||||
|
return { ...base, type: "boolean", default: property.default }
|
||||||
|
case "number":
|
||||||
|
case "integer":
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
type: property.type,
|
||||||
|
minimum: property.minimum,
|
||||||
|
maximum: property.maximum,
|
||||||
|
default: property.default,
|
||||||
|
}
|
||||||
|
case "array":
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
type: "multiselect",
|
||||||
|
options:
|
||||||
|
"anyOf" in property.items
|
||||||
|
? property.items.anyOf.map((option) => ({ value: option.const, label: option.title }))
|
||||||
|
: property.items.enum.map((value) => ({ value, label: value })),
|
||||||
|
custom: false,
|
||||||
|
minItems: property.minItems,
|
||||||
|
maxItems: property.maxItems,
|
||||||
|
default: property.default,
|
||||||
|
}
|
||||||
|
case "string": {
|
||||||
|
const options =
|
||||||
|
"oneOf" in property
|
||||||
|
? property.oneOf.map((option) => ({ value: option.const, label: option.title }))
|
||||||
|
: "enum" in property
|
||||||
|
? property.enum.map((value, index) => ({
|
||||||
|
value,
|
||||||
|
label: ("enumNames" in property ? property.enumNames?.[index] : undefined) ?? value,
|
||||||
|
}))
|
||||||
|
: undefined
|
||||||
|
return {
|
||||||
|
...base,
|
||||||
|
type: "string",
|
||||||
|
format: "format" in property ? property.format : undefined,
|
||||||
|
minLength: "minLength" in property ? property.minLength : undefined,
|
||||||
|
maxLength: "maxLength" in property ? property.maxLength : undefined,
|
||||||
|
default: property.default,
|
||||||
|
options,
|
||||||
|
custom: options ? false : undefined,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ElicitationProperty = MCPClient.ElicitationFormParams["requestedSchema"]["properties"][string]
|
||||||
|
|||||||
@@ -38,6 +38,124 @@ describe("Form", () => {
|
|||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
it.effect("gates required fields and rejects inactive answers via when", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const service = yield* Form.Service
|
||||||
|
const created = yield* service.create({
|
||||||
|
sessionID: "global",
|
||||||
|
mode: "form",
|
||||||
|
fields: [
|
||||||
|
{ key: "confirm", type: "boolean", required: true },
|
||||||
|
{ key: "reason", type: "string", required: true, when: [{ key: "confirm", op: "eq", value: false }] },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const inactive = yield* service.reply({ id: created.id, answer: { confirm: true, reason: "x" } }).pipe(Effect.flip)
|
||||||
|
expect(inactive).toEqual(new Form.InvalidAnswerError({ id: created.id, message: "Form field is not active: reason" }))
|
||||||
|
|
||||||
|
const missing = yield* service.reply({ id: created.id, answer: { confirm: false } }).pipe(Effect.flip)
|
||||||
|
expect(missing).toEqual(
|
||||||
|
new Form.InvalidAnswerError({ id: created.id, message: "Missing required form field: reason" }),
|
||||||
|
)
|
||||||
|
|
||||||
|
yield* service.reply({ id: created.id, answer: { confirm: false, reason: "not ready" } })
|
||||||
|
expect(yield* service.state(created.id)).toEqual({
|
||||||
|
status: "answered",
|
||||||
|
answer: { confirm: false, reason: "not ready" },
|
||||||
|
})
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it.effect("evaluates when against multiselect answers as inclusion", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const service = yield* Form.Service
|
||||||
|
const options = [
|
||||||
|
{ value: "go", label: "Go" },
|
||||||
|
{ value: "ts", label: "TypeScript" },
|
||||||
|
]
|
||||||
|
const created = yield* service.create({
|
||||||
|
sessionID: "global",
|
||||||
|
mode: "form",
|
||||||
|
fields: [
|
||||||
|
{ key: "langs", type: "multiselect", options },
|
||||||
|
{ key: "goVersion", type: "string", required: true, when: [{ key: "langs", op: "eq", value: "go" }] },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const missing = yield* service.reply({ id: created.id, answer: { langs: ["go", "ts"] } }).pipe(Effect.flip)
|
||||||
|
expect(missing).toEqual(
|
||||||
|
new Form.InvalidAnswerError({ id: created.id, message: "Missing required form field: goVersion" }),
|
||||||
|
)
|
||||||
|
|
||||||
|
yield* service.reply({ id: created.id, answer: { langs: ["ts"] } })
|
||||||
|
expect(yield* service.state(created.id)).toEqual({ status: "answered", answer: { langs: ["ts"] } })
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it.effect("treats unanswered when references as false and cascades inactivity", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const service = yield* Form.Service
|
||||||
|
const created = yield* service.create({
|
||||||
|
sessionID: "global",
|
||||||
|
mode: "form",
|
||||||
|
fields: [
|
||||||
|
{ key: "a", type: "boolean" },
|
||||||
|
{ key: "b", type: "string", when: [{ key: "a", op: "eq", value: true }] },
|
||||||
|
// neq also fails against an unanswered reference, and hiding b cascades here through
|
||||||
|
// the reject-inactive-answers rule: b can never be answered while a is false.
|
||||||
|
{ key: "c", type: "string", required: true, when: [{ key: "b", op: "neq", value: "x" }] },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
const inactive = yield* service.reply({ id: created.id, answer: { a: false, b: "yes" } }).pipe(Effect.flip)
|
||||||
|
expect(inactive).toEqual(new Form.InvalidAnswerError({ id: created.id, message: "Form field is not active: b" }))
|
||||||
|
|
||||||
|
yield* service.reply({ id: created.id, answer: { a: false } })
|
||||||
|
expect(yield* service.state(created.id)).toEqual({ status: "answered", answer: { a: false } })
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
|
it.effect("rejects invalid when definitions at creation", () =>
|
||||||
|
Effect.gen(function* () {
|
||||||
|
const service = yield* Form.Service
|
||||||
|
const flipCreate = (fields: ReadonlyArray<Form.Field>) =>
|
||||||
|
service.create({ sessionID: "global", mode: "form", fields }).pipe(Effect.flip)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
yield* flipCreate([
|
||||||
|
{ key: "b", type: "string", when: [{ key: "missing", op: "eq", value: "x" }] },
|
||||||
|
]),
|
||||||
|
).toEqual(new Form.InvalidFormError({ message: "Form field condition must reference an earlier field: b -> missing" }))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
yield* flipCreate([
|
||||||
|
{ key: "a", type: "string" },
|
||||||
|
{ key: "a", type: "string" },
|
||||||
|
]),
|
||||||
|
).toEqual(new Form.InvalidFormError({ message: "Duplicate form field key: a" }))
|
||||||
|
|
||||||
|
expect(
|
||||||
|
yield* flipCreate([
|
||||||
|
{ key: "a", type: "boolean" },
|
||||||
|
{ key: "b", type: "string", when: [{ key: "a", op: "eq", value: "yes" }] },
|
||||||
|
]),
|
||||||
|
).toEqual(
|
||||||
|
new Form.InvalidFormError({ message: "Form field condition value must be a boolean: b -> a" }),
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(
|
||||||
|
yield* flipCreate([
|
||||||
|
{ key: "a", type: "string", options: [{ value: "x", label: "X" }] },
|
||||||
|
{ key: "b", type: "string", when: [{ key: "a", op: "eq", value: "y" }] },
|
||||||
|
]),
|
||||||
|
).toEqual(
|
||||||
|
new Form.InvalidFormError({
|
||||||
|
message: "Form field condition value must be one of the field's options: b -> a",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
|
||||||
it.effect("cleans up created forms when event publication fails", () =>
|
it.effect("cleans up created forms when event publication fails", () =>
|
||||||
Effect.gen(function* () {
|
Effect.gen(function* () {
|
||||||
const service = yield* Form.Service
|
const service = yield* Form.Service
|
||||||
|
|||||||
@@ -22,10 +22,17 @@ export const Option = Schema.Struct({
|
|||||||
}).annotate({ identifier: "Form.Option" })
|
}).annotate({ identifier: "Form.Option" })
|
||||||
export interface Option extends Schema.Schema.Type<typeof Option> {}
|
export interface Option extends Schema.Schema.Type<typeof Option> {}
|
||||||
|
|
||||||
|
// One visibility condition on a field. A field's `when` is a list of conditions that must all
|
||||||
|
// hold (AND) against the current answers for the field to be active. Semantics:
|
||||||
|
// - `value` must match the referenced field's type; against a multiselect answer, `eq` means
|
||||||
|
// "selection includes value" and `neq` means "selection does not include value".
|
||||||
|
// - An unanswered referenced field makes the condition false for both ops.
|
||||||
|
// - `key` must reference a field defined earlier in the form's field list.
|
||||||
|
// Inactive fields are neither required nor answerable.
|
||||||
export const When = Schema.Struct({
|
export const When = Schema.Struct({
|
||||||
key: Schema.String,
|
key: Schema.String,
|
||||||
op: Schema.Literals(["eq", "neq"]),
|
op: Schema.Literals(["eq", "neq"]),
|
||||||
value: Schema.String,
|
value: Schema.Union([Schema.String, Schema.Number, Schema.Boolean]),
|
||||||
}).annotate({ identifier: "Form.When" })
|
}).annotate({ identifier: "Form.When" })
|
||||||
export interface When extends Schema.Schema.Type<typeof When> {}
|
export interface When extends Schema.Schema.Type<typeof When> {}
|
||||||
|
|
||||||
@@ -34,7 +41,7 @@ const FieldBase = {
|
|||||||
title: Schema.String.pipe(optional),
|
title: Schema.String.pipe(optional),
|
||||||
description: Schema.String.pipe(optional),
|
description: Schema.String.pipe(optional),
|
||||||
required: Schema.Boolean.pipe(optional),
|
required: Schema.Boolean.pipe(optional),
|
||||||
when: When.pipe(optional),
|
when: Schema.Array(When).pipe(optional),
|
||||||
}
|
}
|
||||||
|
|
||||||
export const StringField = Schema.Struct({
|
export const StringField = Schema.Struct({
|
||||||
|
|||||||
@@ -3425,7 +3425,7 @@ export type FormMetadata = {
|
|||||||
export type FormWhen = {
|
export type FormWhen = {
|
||||||
key: string
|
key: string
|
||||||
op: "eq" | "neq"
|
op: "eq" | "neq"
|
||||||
value: string
|
value: string | number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormOption = {
|
export type FormOption = {
|
||||||
@@ -3439,7 +3439,7 @@ export type FormStringField = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen>
|
||||||
type: "string"
|
type: "string"
|
||||||
format?: "email" | "uri" | "date" | "date-time"
|
format?: "email" | "uri" | "date" | "date-time"
|
||||||
minLength?: number
|
minLength?: number
|
||||||
@@ -3456,7 +3456,7 @@ export type FormNumberField = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen>
|
||||||
type: "number"
|
type: "number"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3468,7 +3468,7 @@ export type FormIntegerField = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen>
|
||||||
type: "integer"
|
type: "integer"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -3480,7 +3480,7 @@ export type FormBooleanField = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen>
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
default?: boolean
|
default?: boolean
|
||||||
}
|
}
|
||||||
@@ -3490,7 +3490,7 @@ export type FormMultiselectField = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen>
|
||||||
type: "multiselect"
|
type: "multiselect"
|
||||||
options: Array<FormOption>
|
options: Array<FormOption>
|
||||||
minItems?: number
|
minItems?: number
|
||||||
@@ -6382,12 +6382,18 @@ export type QuestionV2Rejected = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FormWhen1 = {
|
||||||
|
key: string
|
||||||
|
op: "eq" | "neq"
|
||||||
|
value: string | number | "NaN" | "Infinity" | "-Infinity" | boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type FormNumberField1 = {
|
export type FormNumberField1 = {
|
||||||
key: string
|
key: string
|
||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen1>
|
||||||
type: "number"
|
type: "number"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
@@ -6399,7 +6405,7 @@ export type FormIntegerField1 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen1>
|
||||||
type: "integer"
|
type: "integer"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
@@ -7778,7 +7784,7 @@ export type FormNumberField2 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen1>
|
||||||
type: "number"
|
type: "number"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
@@ -7790,7 +7796,7 @@ export type FormIntegerField2 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen
|
when?: Array<FormWhen1>
|
||||||
type: "integer"
|
type: "integer"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
@@ -9659,7 +9665,7 @@ export type FormMetadata2 = {
|
|||||||
export type FormWhen2 = {
|
export type FormWhen2 = {
|
||||||
key: string
|
key: string
|
||||||
op: "eq" | "neq"
|
op: "eq" | "neq"
|
||||||
value: string
|
value: string | number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN" | boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormOption2 = {
|
export type FormOption2 = {
|
||||||
@@ -9673,7 +9679,7 @@ export type FormStringField2 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen2
|
when?: Array<FormWhen2>
|
||||||
type: "string"
|
type: "string"
|
||||||
format?: "email" | "uri" | "date" | "date-time"
|
format?: "email" | "uri" | "date" | "date-time"
|
||||||
minLength?: number
|
minLength?: number
|
||||||
@@ -9690,7 +9696,7 @@ export type FormNumberField3 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen2
|
when?: Array<FormWhen2>
|
||||||
type: "number"
|
type: "number"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -9702,7 +9708,7 @@ export type FormIntegerField3 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen2
|
when?: Array<FormWhen2>
|
||||||
type: "integer"
|
type: "integer"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity" | "Infinity" | "-Infinity" | "NaN"
|
||||||
@@ -9714,7 +9720,7 @@ export type FormBooleanField2 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen2
|
when?: Array<FormWhen2>
|
||||||
type: "boolean"
|
type: "boolean"
|
||||||
default?: boolean
|
default?: boolean
|
||||||
}
|
}
|
||||||
@@ -9724,7 +9730,7 @@ export type FormMultiselectField2 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen2
|
when?: Array<FormWhen2>
|
||||||
type: "multiselect"
|
type: "multiselect"
|
||||||
options: Array<FormOption2>
|
options: Array<FormOption2>
|
||||||
minItems?: number
|
minItems?: number
|
||||||
@@ -11102,12 +11108,35 @@ export type FormMetadata1 = {
|
|||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FormWhen12 = {
|
||||||
|
key: string
|
||||||
|
op: "eq" | "neq"
|
||||||
|
value: string | number | "NaN" | "Infinity" | "-Infinity" | boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormStringField1 = {
|
||||||
|
key: string
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
required?: boolean
|
||||||
|
when?: Array<FormWhen12>
|
||||||
|
type: "string"
|
||||||
|
format?: "email" | "uri" | "date" | "date-time"
|
||||||
|
minLength?: number
|
||||||
|
maxLength?: number
|
||||||
|
pattern?: string
|
||||||
|
placeholder?: string
|
||||||
|
default?: string
|
||||||
|
options?: Array<FormOption2>
|
||||||
|
custom?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
export type FormNumberField12 = {
|
export type FormNumberField12 = {
|
||||||
key: string
|
key: string
|
||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen2
|
when?: Array<FormWhen12>
|
||||||
type: "number"
|
type: "number"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
@@ -11119,20 +11148,44 @@ export type FormIntegerField12 = {
|
|||||||
title?: string
|
title?: string
|
||||||
description?: string
|
description?: string
|
||||||
required?: boolean
|
required?: boolean
|
||||||
when?: FormWhen2
|
when?: Array<FormWhen12>
|
||||||
type: "integer"
|
type: "integer"
|
||||||
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
minimum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
maximum?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
default?: number | "NaN" | "Infinity" | "-Infinity"
|
default?: number | "NaN" | "Infinity" | "-Infinity"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type FormBooleanField1 = {
|
||||||
|
key: string
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
required?: boolean
|
||||||
|
when?: Array<FormWhen12>
|
||||||
|
type: "boolean"
|
||||||
|
default?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export type FormMultiselectField1 = {
|
||||||
|
key: string
|
||||||
|
title?: string
|
||||||
|
description?: string
|
||||||
|
required?: boolean
|
||||||
|
when?: Array<FormWhen12>
|
||||||
|
type: "multiselect"
|
||||||
|
options: Array<FormOption2>
|
||||||
|
minItems?: number
|
||||||
|
maxItems?: number
|
||||||
|
custom?: boolean
|
||||||
|
default?: Array<string>
|
||||||
|
}
|
||||||
|
|
||||||
export type FormFormInfo1 = {
|
export type FormFormInfo1 = {
|
||||||
id: string
|
id: string
|
||||||
sessionID: string
|
sessionID: string
|
||||||
title?: string
|
title?: string
|
||||||
metadata?: FormMetadata1
|
metadata?: FormMetadata1
|
||||||
mode: "form"
|
mode: "form"
|
||||||
fields: Array<FormStringField2 | FormNumberField12 | FormIntegerField12 | FormBooleanField2 | FormMultiselectField2>
|
fields: Array<FormStringField1 | FormNumberField12 | FormIntegerField12 | FormBooleanField1 | FormMultiselectField1>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FormUrlInfo1 = {
|
export type FormUrlInfo1 = {
|
||||||
|
|||||||
@@ -61,14 +61,12 @@ export const FormHandler = HttpApiBuilder.group(Api, "server.form", (handlers) =
|
|||||||
return Effect.succeed({ ...common, mode: "url" as const, url: ctx.payload.url })
|
return Effect.succeed({ ...common, mode: "url" as const, url: ctx.payload.url })
|
||||||
})()
|
})()
|
||||||
|
|
||||||
const created = yield* form
|
const created = yield* form.create(input).pipe(
|
||||||
.create(input)
|
Effect.catchTags({
|
||||||
.pipe(
|
"Form.AlreadyExistsError": (error) => new ConflictError({ resource: error.id, message: error.message }),
|
||||||
Effect.catchTag(
|
"Form.InvalidFormError": (error) => new InvalidRequestError({ message: error.message, field: "fields" }),
|
||||||
"Form.AlreadyExistsError",
|
}),
|
||||||
(error) => new ConflictError({ resource: error.id, message: error.message }),
|
)
|
||||||
),
|
|
||||||
)
|
|
||||||
return { data: created }
|
return { data: created }
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user