mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 12:11:56 +00:00
add documentation for ai agents (#3115)
* add documentation for ai agents * docs: consolidate CLAUDE.md and CONTRIBUTING.md, add style guidelines - Refactor CLAUDE.md to reference CONTRIBUTING.md for build/test/format info - Expand CONTRIBUTING.md with comprehensive build targets, env vars, and testing - Add code style guidelines section with conventional commits - Standardize SDK prettier config to use single quotes (matching web) - Add project-level Claude Code settings to disable co-author attribution * style(sdk): apply prettier with single quotes Run prettier across sdk/base and sdk/package to apply the standardized quote style (single quotes matching web). * docs: add USER.md for per-developer TODO filtering - Add agents/USER.md to .gitignore (contains user identifier) - Document session startup flow in CLAUDE.md: - Create USER.md if missing, prompting for identifier - Filter TODOs by @username tags - Offer relevant TODOs on session start * docs: add i18n documentation task to agent TODOs * docs: document i18n ID patterns in core/ Add agents/i18n-patterns.md covering rust-i18n setup, translation file format, t!() macro usage, key naming conventions, and locale selection. Remove completed TODO item and add reference in CLAUDE.md. * chore: clarify that all builds work on any OS with Docker
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import * as T from "../types"
|
||||
import * as IST from "../actions/input/inputSpecTypes"
|
||||
import { Action, ActionInfo } from "./setupActions"
|
||||
import { ExtractInputSpecType } from "./input/builder/inputSpec"
|
||||
import * as T from '../types'
|
||||
import * as IST from '../actions/input/inputSpecTypes'
|
||||
import { Action, ActionInfo } from './setupActions'
|
||||
import { ExtractInputSpecType } from './input/builder/inputSpec'
|
||||
|
||||
export type RunActionInput<Input> =
|
||||
| Input
|
||||
@@ -53,17 +53,17 @@ type TaskBase = {
|
||||
replayId?: string
|
||||
}
|
||||
type TaskInput<T extends ActionInfo<T.ActionId, any>> = {
|
||||
kind: "partial"
|
||||
kind: 'partial'
|
||||
value: T.DeepPartial<GetActionInputType<T>>
|
||||
}
|
||||
export type TaskOptions<T extends ActionInfo<T.ActionId, any>> = TaskBase &
|
||||
(
|
||||
| {
|
||||
when?: Exclude<T.TaskTrigger, { condition: "input-not-matches" }>
|
||||
when?: Exclude<T.TaskTrigger, { condition: 'input-not-matches' }>
|
||||
input?: TaskInput<T>
|
||||
}
|
||||
| {
|
||||
when: T.TaskTrigger & { condition: "input-not-matches" }
|
||||
when: T.TaskTrigger & { condition: 'input-not-matches' }
|
||||
input: TaskInput<T>
|
||||
}
|
||||
)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { InputSpec } from "./inputSpec"
|
||||
import { List } from "./list"
|
||||
import { Value } from "./value"
|
||||
import { Variants } from "./variants"
|
||||
import { InputSpec } from './inputSpec'
|
||||
import { List } from './list'
|
||||
import { Value } from './value'
|
||||
import { Variants } from './variants'
|
||||
|
||||
export { InputSpec as InputSpec, List, Value, Variants }
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { ValueSpec } from "../inputSpecTypes"
|
||||
import { Value } from "./value"
|
||||
import { _ } from "../../../util"
|
||||
import { Effects } from "../../../Effects"
|
||||
import { Parser, object } from "ts-matches"
|
||||
import { DeepPartial } from "../../../types"
|
||||
import { ValueSpec } from '../inputSpecTypes'
|
||||
import { Value } from './value'
|
||||
import { _ } from '../../../util'
|
||||
import { Effects } from '../../../Effects'
|
||||
import { Parser, object } from 'ts-matches'
|
||||
import { DeepPartial } from '../../../types'
|
||||
|
||||
export type LazyBuildOptions = {
|
||||
effects: Effects
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { InputSpec, LazyBuild } from "./inputSpec"
|
||||
import { InputSpec, LazyBuild } from './inputSpec'
|
||||
import {
|
||||
ListValueSpecText,
|
||||
Pattern,
|
||||
@@ -6,8 +6,8 @@ import {
|
||||
UniqueBy,
|
||||
ValueSpecList,
|
||||
ValueSpecListOf,
|
||||
} from "../inputSpecTypes"
|
||||
import { Parser, arrayOf, string } from "ts-matches"
|
||||
} from '../inputSpecTypes'
|
||||
import { Parser, arrayOf, string } from 'ts-matches'
|
||||
|
||||
export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
private constructor(
|
||||
@@ -55,7 +55,7 @@ export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
* @description Informs the browser how to behave and which keyboard to display on mobile
|
||||
* @default "text"
|
||||
*/
|
||||
inputmode?: ListValueSpecText["inputmode"]
|
||||
inputmode?: ListValueSpecText['inputmode']
|
||||
/**
|
||||
* @description Displays a button that will generate a random string according to the provided charset and len attributes.
|
||||
*/
|
||||
@@ -65,21 +65,21 @@ export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const validator = arrayOf(string)
|
||||
return new List<string[]>(() => {
|
||||
const spec = {
|
||||
type: "text" as const,
|
||||
type: 'text' as const,
|
||||
placeholder: null,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
masked: false,
|
||||
inputmode: "text" as const,
|
||||
inputmode: 'text' as const,
|
||||
generate: null,
|
||||
patterns: aSpec.patterns || [],
|
||||
...aSpec,
|
||||
}
|
||||
const built: ValueSpecListOf<"text"> = {
|
||||
const built: ValueSpecListOf<'text'> = {
|
||||
description: null,
|
||||
warning: null,
|
||||
default: [],
|
||||
type: "list" as const,
|
||||
type: 'list' as const,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
disabled: false,
|
||||
@@ -106,7 +106,7 @@ export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ListValueSpecText["inputmode"]
|
||||
inputmode?: ListValueSpecText['inputmode']
|
||||
}
|
||||
}>,
|
||||
) {
|
||||
@@ -114,21 +114,21 @@ export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new List<string[]>(async (options) => {
|
||||
const { spec: aSpec, ...a } = await getA(options)
|
||||
const spec = {
|
||||
type: "text" as const,
|
||||
type: 'text' as const,
|
||||
placeholder: null,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
masked: false,
|
||||
inputmode: "text" as const,
|
||||
inputmode: 'text' as const,
|
||||
generate: null,
|
||||
patterns: aSpec.patterns || [],
|
||||
...aSpec,
|
||||
}
|
||||
const built: ValueSpecListOf<"text"> = {
|
||||
const built: ValueSpecListOf<'text'> = {
|
||||
description: null,
|
||||
warning: null,
|
||||
default: [],
|
||||
type: "list" as const,
|
||||
type: 'list' as const,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
disabled: false,
|
||||
@@ -162,7 +162,7 @@ export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const { spec: previousSpecSpec, ...restSpec } = aSpec
|
||||
const built = await previousSpecSpec.build(options)
|
||||
const spec = {
|
||||
type: "object" as const,
|
||||
type: 'object' as const,
|
||||
displayAs: null,
|
||||
uniqueBy: null,
|
||||
...restSpec,
|
||||
@@ -179,7 +179,7 @@ export class List<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
warning: null,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
type: "list" as const,
|
||||
type: 'list' as const,
|
||||
disabled: false,
|
||||
...value,
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { InputSpec, LazyBuild } from "./inputSpec"
|
||||
import { List } from "./list"
|
||||
import { UnionRes, UnionResStaticValidatedAs, Variants } from "./variants"
|
||||
import { InputSpec, LazyBuild } from './inputSpec'
|
||||
import { List } from './list'
|
||||
import { UnionRes, UnionResStaticValidatedAs, Variants } from './variants'
|
||||
import {
|
||||
Pattern,
|
||||
RandomString,
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
ValueSpecHidden,
|
||||
ValueSpecText,
|
||||
ValueSpecTextarea,
|
||||
} from "../inputSpecTypes"
|
||||
import { DefaultString } from "../inputSpecTypes"
|
||||
import { _, once } from "../../../util"
|
||||
} from '../inputSpecTypes'
|
||||
import { DefaultString } from '../inputSpecTypes'
|
||||
import { _, once } from '../../../util'
|
||||
import {
|
||||
Parser,
|
||||
any,
|
||||
@@ -23,8 +23,8 @@ import {
|
||||
number,
|
||||
object,
|
||||
string,
|
||||
} from "ts-matches"
|
||||
import { DeepPartial } from "../../../types"
|
||||
} from 'ts-matches'
|
||||
import { DeepPartial } from '../../../types'
|
||||
|
||||
export const fileInfoParser = object({
|
||||
path: string,
|
||||
@@ -42,7 +42,7 @@ const testForAsRequiredParser = once(
|
||||
function asRequiredParser<Type, Input extends { required: boolean }>(
|
||||
parser: Parser<unknown, Type>,
|
||||
input: Input,
|
||||
): Parser<unknown, AsRequired<Type, Input["required"]>> {
|
||||
): Parser<unknown, AsRequired<Type, Input['required']>> {
|
||||
if (testForAsRequiredParser()(input)) return parser as any
|
||||
return parser.nullable() as any
|
||||
}
|
||||
@@ -92,7 +92,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
spec: {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: "toggle" as const,
|
||||
type: 'toggle' as const,
|
||||
disabled: false,
|
||||
immutable: a.immutable ?? false,
|
||||
...a,
|
||||
@@ -117,7 +117,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
spec: {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: "toggle" as const,
|
||||
type: 'toggle' as const,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...(await a(options)),
|
||||
@@ -191,7 +191,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
* @description Informs the browser how to behave and which keyboard to display on mobile
|
||||
* @default "text"
|
||||
*/
|
||||
inputmode?: ValueSpecText["inputmode"]
|
||||
inputmode?: ValueSpecText['inputmode']
|
||||
/**
|
||||
* @description Once set, the value can never be changed.
|
||||
* @default false
|
||||
@@ -206,7 +206,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new Value<AsRequired<string, Required>>(
|
||||
async () => ({
|
||||
spec: {
|
||||
type: "text" as const,
|
||||
type: 'text' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
masked: false,
|
||||
@@ -214,7 +214,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
patterns: [],
|
||||
inputmode: "text",
|
||||
inputmode: 'text',
|
||||
disabled: false,
|
||||
immutable: a.immutable ?? false,
|
||||
generate: a.generate ?? null,
|
||||
@@ -237,7 +237,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
minLength?: number | null
|
||||
maxLength?: number | null
|
||||
patterns?: Pattern[]
|
||||
inputmode?: ValueSpecText["inputmode"]
|
||||
inputmode?: ValueSpecText['inputmode']
|
||||
disabled?: string | false
|
||||
generate?: null | RandomString
|
||||
}>,
|
||||
@@ -247,7 +247,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
type: "text" as const,
|
||||
type: 'text' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
masked: false,
|
||||
@@ -255,7 +255,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
patterns: [],
|
||||
inputmode: "text",
|
||||
inputmode: 'text',
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
generate: a.generate ?? null,
|
||||
@@ -334,7 +334,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
minRows: 3,
|
||||
maxRows: 6,
|
||||
placeholder: null,
|
||||
type: "textarea" as const,
|
||||
type: 'textarea' as const,
|
||||
disabled: false,
|
||||
immutable: a.immutable ?? false,
|
||||
...a,
|
||||
@@ -371,7 +371,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
minRows: 3,
|
||||
maxRows: 6,
|
||||
placeholder: null,
|
||||
type: "textarea" as const,
|
||||
type: 'textarea' as const,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
@@ -444,7 +444,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new Value<AsRequired<number, Required>>(
|
||||
() => ({
|
||||
spec: {
|
||||
type: "number" as const,
|
||||
type: 'number' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
min: null,
|
||||
@@ -482,7 +482,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
type: "number" as const,
|
||||
type: 'number' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
min: null,
|
||||
@@ -540,7 +540,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new Value<AsRequired<string, Required>>(
|
||||
() => ({
|
||||
spec: {
|
||||
type: "color" as const,
|
||||
type: 'color' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
disabled: false,
|
||||
@@ -568,7 +568,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
type: "color" as const,
|
||||
type: 'color' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
disabled: false,
|
||||
@@ -618,7 +618,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
* @description Informs the browser how to behave and which date/time component to display.
|
||||
* @default "datetime-local"
|
||||
*/
|
||||
inputmode?: ValueSpecDatetime["inputmode"]
|
||||
inputmode?: ValueSpecDatetime['inputmode']
|
||||
min?: string | null
|
||||
max?: string | null
|
||||
/**
|
||||
@@ -631,10 +631,10 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new Value<AsRequired<string, Required>>(
|
||||
() => ({
|
||||
spec: {
|
||||
type: "datetime" as const,
|
||||
type: 'datetime' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
inputmode: "datetime-local",
|
||||
inputmode: 'datetime-local',
|
||||
min: null,
|
||||
max: null,
|
||||
step: null,
|
||||
@@ -654,7 +654,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
warning?: string | null
|
||||
default: string | null
|
||||
required: Required
|
||||
inputmode?: ValueSpecDatetime["inputmode"]
|
||||
inputmode?: ValueSpecDatetime['inputmode']
|
||||
min?: string | null
|
||||
max?: string | null
|
||||
disabled?: false | string
|
||||
@@ -665,10 +665,10 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
type: "datetime" as const,
|
||||
type: 'datetime' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
inputmode: "datetime-local",
|
||||
inputmode: 'datetime-local',
|
||||
min: null,
|
||||
max: null,
|
||||
disabled: false,
|
||||
@@ -740,7 +740,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
spec: {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: "select" as const,
|
||||
type: 'select' as const,
|
||||
disabled: false,
|
||||
immutable: a.immutable ?? false,
|
||||
...a,
|
||||
@@ -766,7 +766,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
spec: {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: "select" as const,
|
||||
type: 'select' as const,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
@@ -837,7 +837,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new Value<(keyof Values & string)[]>(
|
||||
() => ({
|
||||
spec: {
|
||||
type: "multiselect" as const,
|
||||
type: 'multiselect' as const,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
warning: null,
|
||||
@@ -867,7 +867,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
spec: {
|
||||
type: "multiselect" as const,
|
||||
type: 'multiselect' as const,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
warning: null,
|
||||
@@ -915,7 +915,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const built = await spec.build(options as any)
|
||||
return {
|
||||
spec: {
|
||||
type: "object" as const,
|
||||
type: 'object' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...a,
|
||||
@@ -933,7 +933,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
required: Required
|
||||
}) {
|
||||
const buildValue = {
|
||||
type: "file" as const,
|
||||
type: 'file' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...a,
|
||||
@@ -960,7 +960,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new Value<AsRequired<FileInfo, Required>, FileInfo | null>(
|
||||
async (options) => {
|
||||
const spec = {
|
||||
type: "file" as const,
|
||||
type: 'file' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...(await a(options)),
|
||||
@@ -1034,7 +1034,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const built = await a.variants.build(options as any)
|
||||
return {
|
||||
spec: {
|
||||
type: "union" as const,
|
||||
type: 'union' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
disabled: false,
|
||||
@@ -1109,7 +1109,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const built = await newValues.variants.build(options as any)
|
||||
return {
|
||||
spec: {
|
||||
type: "union" as const,
|
||||
type: 'union' as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
...newValues,
|
||||
@@ -1202,7 +1202,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
return new Value<T, typeof parser._TYPE>(async () => {
|
||||
return {
|
||||
spec: {
|
||||
type: "hidden" as const,
|
||||
type: 'hidden' as const,
|
||||
} as ValueSpecHidden,
|
||||
validator: parser,
|
||||
}
|
||||
@@ -1221,7 +1221,7 @@ export class Value<Type extends StaticValidatedAs, StaticValidatedAs = Type> {
|
||||
const validator = await getParser(options)
|
||||
return {
|
||||
spec: {
|
||||
type: "hidden" as const,
|
||||
type: 'hidden' as const,
|
||||
} as ValueSpecHidden,
|
||||
validator,
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { DeepPartial } from "../../../types"
|
||||
import { ValueSpec, ValueSpecUnion } from "../inputSpecTypes"
|
||||
import { DeepPartial } from '../../../types'
|
||||
import { ValueSpec, ValueSpecUnion } from '../inputSpecTypes'
|
||||
import {
|
||||
LazyBuild,
|
||||
InputSpec,
|
||||
ExtractInputSpecType,
|
||||
ExtractInputSpecStaticValidatedAs,
|
||||
} from "./inputSpec"
|
||||
import { Parser, any, anyOf, literal, object } from "ts-matches"
|
||||
} from './inputSpec'
|
||||
import { Parser, any, anyOf, literal, object } from 'ts-matches'
|
||||
|
||||
export type UnionRes<
|
||||
VariantValues extends {
|
||||
@@ -19,10 +19,10 @@ export type UnionRes<
|
||||
> = {
|
||||
[key in keyof VariantValues]: {
|
||||
selection: key
|
||||
value: ExtractInputSpecType<VariantValues[key]["spec"]>
|
||||
value: ExtractInputSpecType<VariantValues[key]['spec']>
|
||||
other?: {
|
||||
[key2 in Exclude<keyof VariantValues & string, key>]?: DeepPartial<
|
||||
ExtractInputSpecType<VariantValues[key2]["spec"]>
|
||||
ExtractInputSpecType<VariantValues[key2]['spec']>
|
||||
>
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,10 @@ export type UnionResStaticValidatedAs<
|
||||
> = {
|
||||
[key in keyof VariantValues]: {
|
||||
selection: key
|
||||
value: ExtractInputSpecStaticValidatedAs<VariantValues[key]["spec"]>
|
||||
value: ExtractInputSpecStaticValidatedAs<VariantValues[key]['spec']>
|
||||
other?: {
|
||||
[key2 in Exclude<keyof VariantValues & string, key>]?: DeepPartial<
|
||||
ExtractInputSpecStaticValidatedAs<VariantValues[key2]["spec"]>
|
||||
ExtractInputSpecStaticValidatedAs<VariantValues[key2]['spec']>
|
||||
>
|
||||
}
|
||||
}
|
||||
@@ -106,7 +106,7 @@ export class Variants<
|
||||
> {
|
||||
private constructor(
|
||||
public build: LazyBuild<{
|
||||
spec: ValueSpecUnion["variants"]
|
||||
spec: ValueSpecUnion['variants']
|
||||
validator: Parser<unknown, UnionRes<VariantValues>>
|
||||
}>,
|
||||
public readonly validator: Parser<
|
||||
@@ -126,7 +126,7 @@ export class Variants<
|
||||
const staticValidators = {} as {
|
||||
[K in keyof VariantValues]: Parser<
|
||||
unknown,
|
||||
ExtractInputSpecStaticValidatedAs<VariantValues[K]["spec"]>
|
||||
ExtractInputSpecStaticValidatedAs<VariantValues[K]['spec']>
|
||||
>
|
||||
}
|
||||
for (const key in a) {
|
||||
@@ -143,7 +143,7 @@ export class Variants<
|
||||
const validators = {} as {
|
||||
[K in keyof VariantValues]: Parser<
|
||||
unknown,
|
||||
ExtractInputSpecType<VariantValues[K]["spec"]>
|
||||
ExtractInputSpecType<VariantValues[K]['spec']>
|
||||
>
|
||||
}
|
||||
const variants = {} as {
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
export * as constants from "./inputSpecConstants"
|
||||
export * as types from "./inputSpecTypes"
|
||||
export * as builder from "./builder"
|
||||
export * as constants from './inputSpecConstants'
|
||||
export * as types from './inputSpecTypes'
|
||||
export * as builder from './builder'
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SmtpValue } from "../../types"
|
||||
import { GetSystemSmtp, Patterns } from "../../util"
|
||||
import { InputSpec, InputSpecOf } from "./builder/inputSpec"
|
||||
import { Value } from "./builder/value"
|
||||
import { Variants } from "./builder/variants"
|
||||
import { SmtpValue } from '../../types'
|
||||
import { GetSystemSmtp, Patterns } from '../../util'
|
||||
import { InputSpec, InputSpecOf } from './builder/inputSpec'
|
||||
import { Value } from './builder/value'
|
||||
import { Variants } from './builder/variants'
|
||||
|
||||
/**
|
||||
* Base SMTP settings, to be used by StartOS for system wide SMTP
|
||||
@@ -11,12 +11,12 @@ export const customSmtp: InputSpec<SmtpValue> = InputSpec.of<
|
||||
InputSpecOf<SmtpValue>
|
||||
>({
|
||||
server: Value.text({
|
||||
name: "SMTP Server",
|
||||
name: 'SMTP Server',
|
||||
required: true,
|
||||
default: null,
|
||||
}),
|
||||
port: Value.number({
|
||||
name: "Port",
|
||||
name: 'Port',
|
||||
required: true,
|
||||
default: 587,
|
||||
min: 1,
|
||||
@@ -24,20 +24,20 @@ export const customSmtp: InputSpec<SmtpValue> = InputSpec.of<
|
||||
integer: true,
|
||||
}),
|
||||
from: Value.text({
|
||||
name: "From Address",
|
||||
name: 'From Address',
|
||||
required: true,
|
||||
default: null,
|
||||
placeholder: "Example Name <test@example.com>",
|
||||
inputmode: "email",
|
||||
placeholder: 'Example Name <test@example.com>',
|
||||
inputmode: 'email',
|
||||
patterns: [Patterns.emailWithName],
|
||||
}),
|
||||
login: Value.text({
|
||||
name: "Login",
|
||||
name: 'Login',
|
||||
required: true,
|
||||
default: null,
|
||||
}),
|
||||
password: Value.text({
|
||||
name: "Password",
|
||||
name: 'Password',
|
||||
required: false,
|
||||
default: null,
|
||||
masked: true,
|
||||
@@ -45,24 +45,24 @@ export const customSmtp: InputSpec<SmtpValue> = InputSpec.of<
|
||||
})
|
||||
|
||||
const smtpVariants = Variants.of({
|
||||
disabled: { name: "Disabled", spec: InputSpec.of({}) },
|
||||
disabled: { name: 'Disabled', spec: InputSpec.of({}) },
|
||||
system: {
|
||||
name: "System Credentials",
|
||||
name: 'System Credentials',
|
||||
spec: InputSpec.of({
|
||||
customFrom: Value.text({
|
||||
name: "Custom From Address",
|
||||
name: 'Custom From Address',
|
||||
description:
|
||||
"A custom from address for this service. If not provided, the system from address will be used.",
|
||||
'A custom from address for this service. If not provided, the system from address will be used.',
|
||||
required: false,
|
||||
default: null,
|
||||
placeholder: "<name>test@example.com",
|
||||
inputmode: "email",
|
||||
placeholder: '<name>test@example.com',
|
||||
inputmode: 'email',
|
||||
patterns: [Patterns.email],
|
||||
}),
|
||||
}),
|
||||
},
|
||||
custom: {
|
||||
name: "Custom Credentials",
|
||||
name: 'Custom Credentials',
|
||||
spec: customSmtp,
|
||||
},
|
||||
})
|
||||
@@ -71,11 +71,11 @@ const smtpVariants = Variants.of({
|
||||
*/
|
||||
export const smtpInputSpec = Value.dynamicUnion(async ({ effects }) => {
|
||||
const smtp = await new GetSystemSmtp(effects).once()
|
||||
const disabled = smtp ? [] : ["system"]
|
||||
const disabled = smtp ? [] : ['system']
|
||||
return {
|
||||
name: "SMTP",
|
||||
description: "Optionally provide an SMTP server for sending emails",
|
||||
default: "disabled",
|
||||
name: 'SMTP',
|
||||
description: 'Optionally provide an SMTP server for sending emails',
|
||||
default: 'disabled',
|
||||
disabled,
|
||||
variants: smtpVariants,
|
||||
}
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
export type InputSpec = Record<string, ValueSpec>
|
||||
export type ValueType =
|
||||
| "text"
|
||||
| "textarea"
|
||||
| "number"
|
||||
| "color"
|
||||
| "datetime"
|
||||
| "toggle"
|
||||
| "select"
|
||||
| "multiselect"
|
||||
| "list"
|
||||
| "object"
|
||||
| "file"
|
||||
| "union"
|
||||
| "hidden"
|
||||
| 'text'
|
||||
| 'textarea'
|
||||
| 'number'
|
||||
| 'color'
|
||||
| 'datetime'
|
||||
| 'toggle'
|
||||
| 'select'
|
||||
| 'multiselect'
|
||||
| 'list'
|
||||
| 'object'
|
||||
| 'file'
|
||||
| 'union'
|
||||
| 'hidden'
|
||||
export type ValueSpec = ValueSpecOf<ValueType>
|
||||
/** core spec types. These types provide the metadata for performing validations */
|
||||
// prettier-ignore
|
||||
@@ -37,13 +37,13 @@ export type ValueSpecText = {
|
||||
description: string | null
|
||||
warning: string | null
|
||||
|
||||
type: "text"
|
||||
type: 'text'
|
||||
patterns: Pattern[]
|
||||
minLength: number | null
|
||||
maxLength: number | null
|
||||
masked: boolean
|
||||
|
||||
inputmode: "text" | "email" | "tel" | "url"
|
||||
inputmode: 'text' | 'email' | 'tel' | 'url'
|
||||
placeholder: string | null
|
||||
|
||||
required: boolean
|
||||
@@ -57,7 +57,7 @@ export type ValueSpecTextarea = {
|
||||
description: string | null
|
||||
warning: string | null
|
||||
|
||||
type: "textarea"
|
||||
type: 'textarea'
|
||||
patterns: Pattern[]
|
||||
placeholder: string | null
|
||||
minLength: number | null
|
||||
@@ -71,7 +71,7 @@ export type ValueSpecTextarea = {
|
||||
}
|
||||
|
||||
export type ValueSpecNumber = {
|
||||
type: "number"
|
||||
type: 'number'
|
||||
min: number | null
|
||||
max: number | null
|
||||
integer: boolean
|
||||
@@ -91,7 +91,7 @@ export type ValueSpecColor = {
|
||||
description: string | null
|
||||
warning: string | null
|
||||
|
||||
type: "color"
|
||||
type: 'color'
|
||||
required: boolean
|
||||
default: string | null
|
||||
disabled: false | string
|
||||
@@ -101,9 +101,9 @@ export type ValueSpecDatetime = {
|
||||
name: string
|
||||
description: string | null
|
||||
warning: string | null
|
||||
type: "datetime"
|
||||
type: 'datetime'
|
||||
required: boolean
|
||||
inputmode: "date" | "time" | "datetime-local"
|
||||
inputmode: 'date' | 'time' | 'datetime-local'
|
||||
min: string | null
|
||||
max: string | null
|
||||
default: string | null
|
||||
@@ -115,7 +115,7 @@ export type ValueSpecSelect = {
|
||||
name: string
|
||||
description: string | null
|
||||
warning: string | null
|
||||
type: "select"
|
||||
type: 'select'
|
||||
default: string | null
|
||||
disabled: false | string | string[]
|
||||
immutable: boolean
|
||||
@@ -127,7 +127,7 @@ export type ValueSpecMultiselect = {
|
||||
description: string | null
|
||||
warning: string | null
|
||||
|
||||
type: "multiselect"
|
||||
type: 'multiselect'
|
||||
minLength: number | null
|
||||
maxLength: number | null
|
||||
disabled: false | string | string[]
|
||||
@@ -139,7 +139,7 @@ export type ValueSpecToggle = {
|
||||
description: string | null
|
||||
warning: string | null
|
||||
|
||||
type: "toggle"
|
||||
type: 'toggle'
|
||||
default: boolean | null
|
||||
disabled: false | string
|
||||
immutable: boolean
|
||||
@@ -149,7 +149,7 @@ export type ValueSpecUnion = {
|
||||
description: string | null
|
||||
warning: string | null
|
||||
|
||||
type: "union"
|
||||
type: 'union'
|
||||
variants: Record<
|
||||
string,
|
||||
{
|
||||
@@ -165,7 +165,7 @@ export type ValueSpecFile = {
|
||||
name: string
|
||||
description: string | null
|
||||
warning: string | null
|
||||
type: "file"
|
||||
type: 'file'
|
||||
extensions: string[]
|
||||
required: boolean
|
||||
}
|
||||
@@ -173,13 +173,13 @@ export type ValueSpecObject = {
|
||||
name: string
|
||||
description: string | null
|
||||
warning: string | null
|
||||
type: "object"
|
||||
type: 'object'
|
||||
spec: InputSpec
|
||||
}
|
||||
export type ValueSpecHidden = {
|
||||
type: "hidden"
|
||||
type: 'hidden'
|
||||
}
|
||||
export type ListValueSpecType = "text" | "object"
|
||||
export type ListValueSpecType = 'text' | 'object'
|
||||
// prettier-ignore
|
||||
export type ListValueSpecOf<T extends ListValueSpecType> =
|
||||
T extends "text" ? ListValueSpecText :
|
||||
@@ -190,7 +190,7 @@ export type ValueSpecListOf<T extends ListValueSpecType> = {
|
||||
name: string
|
||||
description: string | null
|
||||
warning: string | null
|
||||
type: "list"
|
||||
type: 'list'
|
||||
spec: ListValueSpecOf<T>
|
||||
minLength: number | null
|
||||
maxLength: number | null
|
||||
@@ -208,18 +208,18 @@ export type Pattern = {
|
||||
description: string
|
||||
}
|
||||
export type ListValueSpecText = {
|
||||
type: "text"
|
||||
type: 'text'
|
||||
patterns: Pattern[]
|
||||
minLength: number | null
|
||||
maxLength: number | null
|
||||
masked: boolean
|
||||
|
||||
generate: null | RandomString
|
||||
inputmode: "text" | "email" | "tel" | "url"
|
||||
inputmode: 'text' | 'email' | 'tel' | 'url'
|
||||
placeholder: string | null
|
||||
}
|
||||
export type ListValueSpecObject = {
|
||||
type: "object"
|
||||
type: 'object'
|
||||
spec: InputSpec
|
||||
uniqueBy: UniqueBy
|
||||
displayAs: string | null
|
||||
@@ -244,5 +244,5 @@ export function isValueSpecListOf<S extends ListValueSpecType>(
|
||||
t: ValueSpec,
|
||||
s: S,
|
||||
): t is ValueSpecListOf<S> & { spec: ListValueSpecOf<S> } {
|
||||
return "spec" in t && t.spec.type === s
|
||||
return 'spec' in t && t.spec.type === s
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { InputSpec } from "./input/builder"
|
||||
import { ExtractInputSpecType } from "./input/builder/inputSpec"
|
||||
import * as T from "../types"
|
||||
import { once } from "../util"
|
||||
import { InitScript } from "../inits"
|
||||
import { Parser } from "ts-matches"
|
||||
import { InputSpec } from './input/builder'
|
||||
import { ExtractInputSpecType } from './input/builder/inputSpec'
|
||||
import * as T from '../types'
|
||||
import { once } from '../util'
|
||||
import { InitScript } from '../inits'
|
||||
import { Parser } from 'ts-matches'
|
||||
|
||||
type MaybeInputSpec<Type> = {} extends Type ? null : InputSpec<Type>
|
||||
export type Run<A extends Record<string, any>> = (options: {
|
||||
effects: T.Effects
|
||||
input: A
|
||||
spec: T.inputSpecTypes.InputSpec
|
||||
}) => Promise<(T.ActionResult & { version: "1" }) | null | void | undefined>
|
||||
}) => Promise<(T.ActionResult & { version: '1' }) | null | void | undefined>
|
||||
export type GetInput<A extends Record<string, any>> = (options: {
|
||||
effects: T.Effects
|
||||
}) => Promise<null | void | undefined | T.DeepPartial<A>>
|
||||
@@ -65,7 +65,7 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
InputSpecType extends InputSpec<Record<string, any>>,
|
||||
>(
|
||||
id: Id,
|
||||
metadata: MaybeFn<Omit<T.ActionMetadata, "hasInput">>,
|
||||
metadata: MaybeFn<Omit<T.ActionMetadata, 'hasInput'>>,
|
||||
inputSpec: InputSpecType,
|
||||
getInput: GetInput<ExtractInputSpecType<InputSpecType>>,
|
||||
run: Run<ExtractInputSpecType<InputSpecType>>,
|
||||
@@ -80,7 +80,7 @@ export class Action<Id extends T.ActionId, Type extends Record<string, any>>
|
||||
}
|
||||
static withoutInput<Id extends T.ActionId>(
|
||||
id: Id,
|
||||
metadata: MaybeFn<Omit<T.ActionMetadata, "hasInput">>,
|
||||
metadata: MaybeFn<Omit<T.ActionMetadata, 'hasInput'>>,
|
||||
run: Run<{}>,
|
||||
): Action<Id, {}> {
|
||||
return new Action(
|
||||
@@ -156,7 +156,7 @@ export class Actions<
|
||||
}
|
||||
addAction<A extends Action<T.ActionId, any>>(
|
||||
action: A, // TODO: prevent duplicates
|
||||
): Actions<AllActions & { [id in A["id"]]: A }> {
|
||||
): Actions<AllActions & { [id in A['id']]: A }> {
|
||||
return new Actions({ ...this.actions, [action.id]: action })
|
||||
}
|
||||
async init(effects: T.Effects): Promise<void> {
|
||||
|
||||
Reference in New Issue
Block a user