feat: Remove the vault

This commit is contained in:
Blu-J
2023-05-30 17:36:30 -06:00
parent 613bf74180
commit 3f5dbc6a4b
24 changed files with 308 additions and 515 deletions

View File

@@ -52,6 +52,7 @@ import {
setupInterfaces, setupInterfaces,
} from "./interfaces/setupInterfaces" } from "./interfaces/setupInterfaces"
import { successFailure } from "./trigger/successFailure" import { successFailure } from "./trigger/successFailure"
import { SetupExports } from "./inits/setupExports"
// prettier-ignore // prettier-ignore
type AnyNeverCond<T extends any[], Then, Else> = type AnyNeverCond<T extends any[], Then, Else> =
@@ -60,42 +61,37 @@ type AnyNeverCond<T extends any[], Then, Else> =
T extends [any, ...infer U] ? AnyNeverCond<U,Then, Else> : T extends [any, ...infer U] ? AnyNeverCond<U,Then, Else> :
never never
export class StartSdk<Manifest extends SDKManifest, Store, Vault> { export class StartSdk<Manifest extends SDKManifest, Store> {
private constructor(readonly manifest: Manifest) {} private constructor(readonly manifest: Manifest) {}
static of() { static of() {
return new StartSdk<never, never, never>(null as never) return new StartSdk<never, never>(null as never)
} }
withManifest<Manifest extends SDKManifest = never>(manifest: Manifest) { withManifest<Manifest extends SDKManifest = never>(manifest: Manifest) {
return new StartSdk<Manifest, Store, Vault>(manifest) return new StartSdk<Manifest, Store>(manifest)
} }
withStore<Store extends Record<string, any>>() { withStore<Store extends Record<string, any>>() {
return new StartSdk<Manifest, Store, Vault>(this.manifest) return new StartSdk<Manifest, Store>(this.manifest)
}
withVault<Vault extends Record<string, string>>() {
return new StartSdk<Manifest, Store, Vault>(this.manifest)
} }
build( build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) {
isReady: AnyNeverCond<[Manifest, Store, Vault], "Build not ready", true>,
) {
return { return {
configConstants: { smtpConfig }, configConstants: { smtpConfig },
createAction: < createAction: <
ConfigType extends ConfigType extends
| Record<string, any> | Record<string, any>
| Config<any, any, any> | Config<any, any>
| Config<any, never, never>, | Config<any, never>,
Type extends Record<string, any> = ExtractConfigType<ConfigType>, Type extends Record<string, any> = ExtractConfigType<ConfigType>,
>( >(
metaData: Omit<ActionMetadata, "input"> & { metaData: Omit<ActionMetadata, "input"> & {
input: Config<Type, Store, Vault> | Config<Type, never, never> input: Config<Type, Store> | Config<Type, never>
}, },
fn: (options: { fn: (options: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
input: Type input: Type
}) => Promise<ActionResult>, }) => Promise<ActionResult>,
) => createAction<Store, Vault, ConfigType, Type>(metaData, fn), ) => createAction<Store, ConfigType, Type>(metaData, fn),
HealthCheck: { HealthCheck: {
of: healthCheck, of: healthCheck,
}, },
@@ -106,84 +102,78 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
}, },
patterns, patterns,
setupActions: (...createdActions: CreatedAction<any, any, any>[]) => setupActions: (...createdActions: CreatedAction<any, any, any>[]) =>
setupActions<Store, Vault>(...createdActions), setupActions<Store>(...createdActions),
setupBackups: (...args: SetupBackupsParams<Manifest>) => setupBackups: (...args: SetupBackupsParams<Manifest>) =>
setupBackups<Manifest>(...args), setupBackups<Manifest>(...args),
setupConfig: < setupConfig: <
ConfigType extends ConfigType extends Config<any, Store> | Config<any, never>,
| Config<any, Store, Vault>
| Config<any, never, never>,
Type extends Record<string, any> = ExtractConfigType<ConfigType>, Type extends Record<string, any> = ExtractConfigType<ConfigType>,
>( >(
spec: ConfigType, spec: ConfigType,
write: Save<Store, Vault, Type, Manifest>, write: Save<Store, Type, Manifest>,
read: Read<Store, Vault, Type>, read: Read<Store, Type>,
) => ) => setupConfig<Store, ConfigType, Manifest, Type>(spec, write, read),
setupConfig<Store, Vault, ConfigType, Manifest, Type>(
spec,
write,
read,
),
setupConfigRead: < setupConfigRead: <
ConfigSpec extends ConfigSpec extends
| Config<Record<string, any>, any, any> | Config<Record<string, any>, any>
| Config<Record<string, never>, never, never>, | Config<Record<string, never>, never>,
>( >(
_configSpec: ConfigSpec, _configSpec: ConfigSpec,
fn: Read<Store, Vault, ConfigSpec>, fn: Read<Store, ConfigSpec>,
) => fn, ) => fn,
setupConfigSave: < setupConfigSave: <
ConfigSpec extends ConfigSpec extends
| Config<Record<string, any>, any, any> | Config<Record<string, any>, any>
| Config<Record<string, never>, never, never>, | Config<Record<string, never>, never>,
>( >(
_configSpec: ConfigSpec, _configSpec: ConfigSpec,
fn: Save<Store, Vault, ConfigSpec, Manifest>, fn: Save<Store, ConfigSpec, Manifest>,
) => fn, ) => fn,
setupDependencyConfig: <Input extends Record<string, any>>( setupDependencyConfig: <Input extends Record<string, any>>(
config: Config<Input, Store, Vault> | Config<Input, never, never>, config: Config<Input, Store> | Config<Input, never>,
autoConfigs: { autoConfigs: {
[K in keyof Manifest["dependencies"]]: DependencyConfig< [K in keyof Manifest["dependencies"]]: DependencyConfig<
Store, Store,
Vault,
Input, Input,
any any
> >
}, },
) => ) => setupDependencyConfig<Store, Input, Manifest>(config, autoConfigs),
setupDependencyConfig<Store, Vault, Input, Manifest>( setupExports: (fn: SetupExports<Store>) => fn,
config,
autoConfigs,
),
setupDependencyMounts, setupDependencyMounts,
setupInit: ( setupInit: (
migrations: Migrations<Store, Vault>, migrations: Migrations<Store>,
install: Install<Store, Vault>, install: Install<Store>,
uninstall: Uninstall<Store, Vault>, uninstall: Uninstall<Store>,
setInterfaces: SetInterfaces<Store, Vault, any, any>, setInterfaces: SetInterfaces<Store, any, any>,
setupExports: SetupExports<Store>,
) => ) =>
setupInit<Store, Vault>(migrations, install, uninstall, setInterfaces), setupInit<Store>(
setupInstall: (fn: InstallFn<Store, Vault>) => Install.of(fn), migrations,
install,
uninstall,
setInterfaces,
setupExports,
),
setupInstall: (fn: InstallFn<Store>) => Install.of(fn),
setupInterfaces: < setupInterfaces: <
ConfigInput extends Record<string, any>, ConfigInput extends Record<string, any>,
Output extends InterfacesReceipt, Output extends InterfacesReceipt,
>( >(
config: Config<ConfigInput, Store, Vault>, config: Config<ConfigInput, Store>,
fn: SetInterfaces<Store, Vault, ConfigInput, Output>, fn: SetInterfaces<Store, ConfigInput, Output>,
) => setupInterfaces(config, fn), ) => setupInterfaces(config, fn),
setupMain: ( setupMain: (
fn: (o: { fn: (o: {
effects: Effects effects: Effects
started(onTerm: () => void): null started(onTerm: () => void): null
utils: Utils<Store, Vault, {}> utils: Utils<Store, {}>
}) => Promise<Daemons<any>>, }) => Promise<Daemons<any>>,
) => setupMain<Store, Vault>(fn), ) => setupMain<Store>(fn),
setupMigrations: <Migrations extends Array<Migration<Store, Vault, any>>>( setupMigrations: <Migrations extends Array<Migration<Store, any>>>(
...migrations: EnsureUniqueId<Migrations> ...migrations: EnsureUniqueId<Migrations>
) => ) => setupMigrations<Store, Migrations>(this.manifest, ...migrations),
setupMigrations<Store, Vault, Migrations>(this.manifest, ...migrations), setupUninstall: (fn: UninstallFn<Store>) => setupUninstall<Store>(fn),
setupUninstall: (fn: UninstallFn<Store, Vault>) =>
setupUninstall<Store, Vault>(fn),
trigger: { trigger: {
defaultTrigger, defaultTrigger,
cooldownTrigger, cooldownTrigger,
@@ -202,13 +192,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
}, },
Config: { Config: {
of: < of: <
Spec extends Record< Spec extends Record<string, Value<any, Store> | Value<any, never>>,
string,
Value<any, Store, Vault> | Value<any, never, never>
>,
>( >(
spec: Spec, spec: Spec,
) => Config.of<Spec, Store, Vault>(spec), ) => Config.of<Spec, Store>(spec),
}, },
Daemons: { of: Daemons.of }, Daemons: { of: Daemons.of },
DependencyConfig: { DependencyConfig: {
@@ -220,20 +207,16 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
remoteConfig, remoteConfig,
dependencyConfig, dependencyConfig,
}: { }: {
localConfig: localConfig: Config<LocalConfig, Store> | Config<LocalConfig, never>
| Config<LocalConfig, Store, Vault> remoteConfig: Config<RemoteConfig, any> | Config<RemoteConfig, never>
| Config<LocalConfig, never, never>
remoteConfig:
| Config<RemoteConfig, any, any>
| Config<RemoteConfig, never, never>
dependencyConfig: (options: { dependencyConfig: (options: {
effects: Effects effects: Effects
localConfig: LocalConfig localConfig: LocalConfig
remoteConfig: RemoteConfig remoteConfig: RemoteConfig
utils: Utils<Store, Vault> utils: Utils<Store>
}) => Promise<void | DeepPartial<RemoteConfig>> }) => Promise<void | DeepPartial<RemoteConfig>>
}) { }) {
return new DependencyConfig<Store, Vault, LocalConfig, RemoteConfig>( return new DependencyConfig<Store, LocalConfig, RemoteConfig>(
dependencyConfig, dependencyConfig,
) )
}, },
@@ -252,15 +235,14 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
maxLength?: number | null maxLength?: number | null
}, },
aSpec: { aSpec: {
spec: Config<Type, Store, Vault> spec: Config<Type, Store>
displayAs?: null | string displayAs?: null | string
uniqueBy?: null | UniqueBy uniqueBy?: null | UniqueBy
}, },
) => List.obj<Type, Store, Vault>(a, aSpec), ) => List.obj<Type, Store>(a, aSpec),
dynamicText: ( dynamicText: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -283,11 +265,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
} }
} }
>, >,
) => List.dynamicText<Store, Vault>(getA), ) => List.dynamicText<Store>(getA),
dynamicNumber: ( dynamicNumber: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -307,20 +288,17 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
} }
} }
>, >,
) => List.dynamicNumber<Store, Vault>(getA), ) => List.dynamicNumber<Store>(getA),
}, },
Migration: { Migration: {
of: <Version extends ManifestVersion>(options: { of: <Version extends ManifestVersion>(options: {
version: Version version: Version
up: (opts: { up: (opts: { effects: Effects; utils: Utils<Store> }) => Promise<void>
effects: Effects
utils: Utils<Store, Vault>
}) => Promise<void>
down: (opts: { down: (opts: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
}) => Promise<void> }) => Promise<void>
}) => Migration.of<Store, Vault, Version>(options), }) => Migration.of<Store, Version>(options),
}, },
Value: { Value: {
toggle: Value.toggle, toggle: Value.toggle,
@@ -337,7 +315,6 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
dynamicToggle: ( dynamicToggle: (
a: LazyBuild< a: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -346,11 +323,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
disabled?: false | string disabled?: false | string
} }
>, >,
) => Value.dynamicToggle<Store, Vault>(a), ) => Value.dynamicToggle<Store>(a),
dynamicText: ( dynamicText: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -368,11 +344,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
generate?: null | RandomString generate?: null | RandomString
} }
>, >,
) => Value.dynamicText<Store, Vault>(getA), ) => Value.dynamicText<Store>(getA),
dynamicTextarea: ( dynamicTextarea: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -385,11 +360,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
generate?: null | RandomString generate?: null | RandomString
} }
>, >,
) => Value.dynamicTextarea<Store, Vault>(getA), ) => Value.dynamicTextarea<Store>(getA),
dynamicNumber: ( dynamicNumber: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -405,11 +379,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
disabled?: false | string disabled?: false | string
} }
>, >,
) => Value.dynamicNumber<Store, Vault>(getA), ) => Value.dynamicNumber<Store>(getA),
dynamicColor: ( dynamicColor: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -419,11 +392,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
disabled?: false | string disabled?: false | string
} }
>, >,
) => Value.dynamicColor<Store, Vault>(getA), ) => Value.dynamicColor<Store>(getA),
dynamicDatetime: ( dynamicDatetime: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -436,11 +408,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
disabled?: false | string disabled?: false | string
} }
>, >,
) => Value.dynamicDatetime<Store, Vault>(getA), ) => Value.dynamicDatetime<Store>(getA),
dynamicSelect: ( dynamicSelect: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -450,11 +421,10 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
disabled?: false | string disabled?: false | string
} }
>, >,
) => Value.dynamicSelect<Store, Vault>(getA), ) => Value.dynamicSelect<Store>(getA),
dynamicMultiselect: ( dynamicMultiselect: (
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -466,23 +436,21 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
disabled?: false | string disabled?: false | string
} }
>, >,
) => Value.dynamicMultiselect<Store, Vault>(getA), ) => Value.dynamicMultiselect<Store>(getA),
filteredUnion: < filteredUnion: <
Required extends RequiredDefault<string>, Required extends RequiredDefault<string>,
Type extends Record<string, any>, Type extends Record<string, any>,
>( >(
getDisabledFn: LazyBuild<Store, Vault, string[]>, getDisabledFn: LazyBuild<Store, string[]>,
a: { a: {
name: string name: string
description?: string | null description?: string | null
warning?: string | null warning?: string | null
required: Required required: Required
}, },
aVariants: aVariants: Variants<Type, Store> | Variants<Type, never>,
| Variants<Type, Store, Vault>
| Variants<Type, never, never>,
) => ) =>
Value.filteredUnion<Required, Type, Store, Vault>( Value.filteredUnion<Required, Type, Store>(
getDisabledFn, getDisabledFn,
a, a,
aVariants, aVariants,
@@ -494,7 +462,6 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
>( >(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
disabled: string[] | false | string disabled: string[] | false | string
name: string name: string
@@ -503,22 +470,20 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
required: Required required: Required
} }
>, >,
aVariants: aVariants: Variants<Type, Store> | Variants<Type, never>,
| Variants<Type, Store, Vault> ) => Value.dynamicUnion<Required, Type, Store>(getA, aVariants),
| Variants<Type, never, never>,
) => Value.dynamicUnion<Required, Type, Store, Vault>(getA, aVariants),
}, },
Variants: { Variants: {
of: < of: <
VariantValues extends { VariantValues extends {
[K in string]: { [K in string]: {
name: string name: string
spec: Config<any, Store, Vault> spec: Config<any, Store>
} }
}, },
>( >(
a: VariantValues, a: VariantValues,
) => Variants.of<VariantValues, Store, Vault>(a), ) => Variants.of<VariantValues, Store>(a),
}, },
} }
} }

View File

@@ -5,47 +5,45 @@ import { Utils, utils } from "../util/utils"
export class CreatedAction< export class CreatedAction<
Store, Store,
Vault,
ConfigType extends ConfigType extends
| Record<string, any> | Record<string, any>
| Config<any, Store, Vault> | Config<any, Store>
| Config<any, never, never>, | Config<any, never>,
Type extends Record<string, any> = ExtractConfigType<ConfigType>, Type extends Record<string, any> = ExtractConfigType<ConfigType>,
> { > {
private constructor( private constructor(
public readonly myMetaData: Omit<ActionMetadata, "input">, public readonly myMetaData: Omit<ActionMetadata, "input">,
readonly fn: (options: { readonly fn: (options: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
input: Type input: Type
}) => Promise<ActionResult>, }) => Promise<ActionResult>,
readonly input: Config<Type, Store, Vault>, readonly input: Config<Type, Store>,
) {} ) {}
public validator = this.input.validator public validator = this.input.validator
static of< static of<
Store, Store,
Vault,
ConfigType extends ConfigType extends
| Record<string, any> | Record<string, any>
| Config<any, any, any> | Config<any, any>
| Config<any, never, never>, | Config<any, never>,
Type extends Record<string, any> = ExtractConfigType<ConfigType>, Type extends Record<string, any> = ExtractConfigType<ConfigType>,
>( >(
metaData: Omit<ActionMetadata, "input"> & { metaData: Omit<ActionMetadata, "input"> & {
input: Config<Type, Store, Vault> | Config<Type, never, never> input: Config<Type, Store> | Config<Type, never>
}, },
fn: (options: { fn: (options: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
input: Type input: Type
}) => Promise<ActionResult>, }) => Promise<ActionResult>,
) { ) {
const { input, ...rest } = metaData const { input, ...rest } = metaData
return new CreatedAction<Store, Vault, ConfigType, Type>( return new CreatedAction<Store, ConfigType, Type>(
rest, rest,
fn, fn,
input as Config<Type, Store, Vault>, input as Config<Type, Store>,
) )
} }
@@ -67,7 +65,7 @@ export class CreatedAction<
async ActionMetadata(options: { async ActionMetadata(options: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
}): Promise<ActionMetadata> { }): Promise<ActionMetadata> {
return { return {
...this.myMetaData, ...this.myMetaData,

View File

@@ -3,11 +3,11 @@ import { createUtils } from "../util"
import { once } from "../util/once" import { once } from "../util/once"
import { CreatedAction } from "./createAction" import { CreatedAction } from "./createAction"
export function setupActions<Store, Vault>( export function setupActions<Store>(
...createdActions: CreatedAction<Store, Vault, any>[] ...createdActions: CreatedAction<Store, any>[]
) { ) {
const myActions = once(() => { const myActions = once(() => {
const actions: Record<string, CreatedAction<Store, Vault, any>> = {} const actions: Record<string, CreatedAction<Store, any>> = {}
for (const action of createdActions) { for (const action of createdActions) {
actions[action.myMetaData.id] = action actions[action.myMetaData.id] = action
} }
@@ -21,7 +21,7 @@ export function setupActions<Store, Vault>(
return myActions() return myActions()
}, },
async actionsMetadata({ effects }: { effects: Effects }) { async actionsMetadata({ effects }: { effects: Effects }) {
const utils = createUtils<Store, Vault>(effects) const utils = createUtils<Store>(effects)
return Promise.all( return Promise.all(
createdActions.map((x) => x.ActionMetadata({ effects, utils })), createdActions.map((x) => x.ActionMetadata({ effects, utils })),
) )

View File

@@ -5,28 +5,24 @@ import { _ } from "../../util"
import { Effects } from "../../types" import { Effects } from "../../types"
import { Parser, object } from "ts-matches" import { Parser, object } from "ts-matches"
export type LazyBuildOptions<Store, Vault> = { export type LazyBuildOptions<Store> = {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
} }
export type LazyBuild<Store, Vault, ExpectedOut> = ( export type LazyBuild<Store, ExpectedOut> = (
options: LazyBuildOptions<Store, Vault>, options: LazyBuildOptions<Store>,
) => Promise<ExpectedOut> | ExpectedOut ) => Promise<ExpectedOut> | ExpectedOut
// prettier-ignore // prettier-ignore
export type ExtractConfigType<A extends Record<string, any> | Config<Record<string, any>, any, any> | Config<Record<string, any>, never, never>> = export type ExtractConfigType<A extends Record<string, any> | Config<Record<string, any>, any> | Config<Record<string, any>, never>> =
A extends Config<infer B, any, any> | Config<infer B, never, never> ? B : A extends Config<infer B, any> | Config<infer B, never> ? B :
A A
export type ConfigSpecOf< export type ConfigSpecOf<A extends Record<string, any>, Store = never> = {
A extends Record<string, any>, [K in keyof A]: Value<A[K], Store>
Store = never,
Vault = never,
> = {
[K in keyof A]: Value<A[K], Store, Vault>
} }
export type MaybeLazyValues<A> = LazyBuild<any, any, A> | A export type MaybeLazyValues<A> = LazyBuild<any, A> | A
/** /**
* Configs are the specs that are used by the os configuration form for this service. * Configs are the specs that are used by the os configuration form for this service.
* Here is an example of a simple configuration * Here is an example of a simple configuration
@@ -83,20 +79,14 @@ export const addNodesSpec = Config.of({ hostname: hostname, port: port });
``` ```
*/ */
export class Config< export class Config<Type extends Record<string, any>, Store = never> {
Type extends Record<string, any>,
Store = never,
Vault = never,
> {
private constructor( private constructor(
private readonly spec: { private readonly spec: {
[K in keyof Type]: [K in keyof Type]: Value<Type[K], Store> | Value<Type[K], never>
| Value<Type[K], Store, Vault>
| Value<Type[K], never, never>
}, },
public validator: Parser<unknown, Type>, public validator: Parser<unknown, Type>,
) {} ) {}
async build(options: LazyBuildOptions<Store, Vault>) { async build(options: LazyBuildOptions<Store>) {
const answer = {} as { const answer = {} as {
[K in keyof Type]: ValueSpec [K in keyof Type]: ValueSpec
} }
@@ -107,12 +97,8 @@ export class Config<
} }
static of< static of<
Spec extends Record< Spec extends Record<string, Value<any, Store> | Value<any, never>>,
string,
Value<any, Store, Vault> | Value<any, never, never>
>,
Store = never, Store = never,
Vault = never,
>(spec: Spec) { >(spec: Spec) {
const validatorObj = {} as { const validatorObj = {} as {
[K in keyof Spec]: Parser<unknown, any> [K in keyof Spec]: Parser<unknown, any>
@@ -124,13 +110,12 @@ export class Config<
return new Config< return new Config<
{ {
[K in keyof Spec]: Spec[K] extends [K in keyof Spec]: Spec[K] extends
| Value<infer T, Store, Vault> | Value<infer T, Store>
| Value<infer T, never, never> | Value<infer T, never>
? T ? T
: never : never
}, },
Store, Store
Vault
>(spec, validator as any) >(spec, validator as any)
} }
@@ -149,6 +134,6 @@ export class Config<
``` ```
*/ */
withStore<NewStore extends Store extends never ? any : Store>() { withStore<NewStore extends Store extends never ? any : Store>() {
return this as any as Config<Type, NewStore, Vault> return this as any as Config<Type, NewStore>
} }
} }

View File

@@ -22,9 +22,9 @@ export const authorizationList = List.string({
export const auth = Value.list(authorizationList); export const auth = Value.list(authorizationList);
``` ```
*/ */
export class List<Type, Store, Vault> { export class List<Type, Store> {
private constructor( private constructor(
public build: LazyBuild<Store, Vault, ValueSpecList>, public build: LazyBuild<Store, ValueSpecList>,
public validator: Parser<unknown, Type>, public validator: Parser<unknown, Type>,
) {} ) {}
static text( static text(
@@ -49,7 +49,7 @@ export class List<Type, Store, Vault> {
generate?: null | RandomString generate?: null | RandomString
}, },
) { ) {
return new List<string[], never, never>(() => { return new List<string[], never>(() => {
const spec = { const spec = {
type: "text" as const, type: "text" as const,
placeholder: null, placeholder: null,
@@ -74,10 +74,9 @@ export class List<Type, Store, Vault> {
return built return built
}, arrayOf(string)) }, arrayOf(string))
} }
static dynamicText<Store = never, Vault = never>( static dynamicText<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -101,7 +100,7 @@ export class List<Type, Store, Vault> {
} }
>, >,
) { ) {
return new List<string[], Store, Vault>(async (options) => { return new List<string[], Store>(async (options) => {
const { spec: aSpec, ...a } = await getA(options) const { spec: aSpec, ...a } = await getA(options)
const spec = { const spec = {
type: "text" as const, type: "text" as const,
@@ -146,7 +145,7 @@ export class List<Type, Store, Vault> {
placeholder?: string | null placeholder?: string | null
}, },
) { ) {
return new List<number[], never, never>(() => { return new List<number[], never>(() => {
const spec = { const spec = {
type: "number" as const, type: "number" as const,
placeholder: null, placeholder: null,
@@ -170,10 +169,9 @@ export class List<Type, Store, Vault> {
return built return built
}, arrayOf(number)) }, arrayOf(number))
} }
static dynamicNumber<Store = never, Vault = never>( static dynamicNumber<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -194,7 +192,7 @@ export class List<Type, Store, Vault> {
} }
>, >,
) { ) {
return new List<number[], Store, Vault>(async (options) => { return new List<number[], Store>(async (options) => {
const { spec: aSpec, ...a } = await getA(options) const { spec: aSpec, ...a } = await getA(options)
const spec = { const spec = {
type: "number" as const, type: "number" as const,
@@ -218,7 +216,7 @@ export class List<Type, Store, Vault> {
} }
}, arrayOf(number)) }, arrayOf(number))
} }
static obj<Type extends Record<string, any>, Store, Vault>( static obj<Type extends Record<string, any>, Store>(
a: { a: {
name: string name: string
description?: string | null description?: string | null
@@ -229,12 +227,12 @@ export class List<Type, Store, Vault> {
maxLength?: number | null maxLength?: number | null
}, },
aSpec: { aSpec: {
spec: Config<Type, Store, Vault> spec: Config<Type, Store>
displayAs?: null | string displayAs?: null | string
uniqueBy?: null | UniqueBy uniqueBy?: null | UniqueBy
}, },
) { ) {
return new List<Type[], Store, Vault>(async (options) => { return new List<Type[], Store>(async (options) => {
const { spec: previousSpecSpec, ...restSpec } = aSpec const { spec: previousSpecSpec, ...restSpec } = aSpec
const specSpec = await previousSpecSpec.build(options) const specSpec = await previousSpecSpec.build(options)
const spec = { const spec = {
@@ -276,6 +274,6 @@ export class List<Type, Store, Vault> {
``` ```
*/ */
withStore<NewStore extends Store extends never ? any : Store>() { withStore<NewStore extends Store extends never ? any : Store>() {
return this as any as List<Type, NewStore, Vault> return this as any as List<Type, NewStore>
} }
} }

View File

@@ -94,9 +94,9 @@ const username = Value.string({
}); });
``` ```
*/ */
export class Value<Type, Store, Vault> { export class Value<Type, Store> {
protected constructor( protected constructor(
public build: LazyBuild<Store, Vault, ValueSpec>, public build: LazyBuild<Store, ValueSpec>,
public validator: Parser<unknown, Type>, public validator: Parser<unknown, Type>,
) {} ) {}
static toggle(a: { static toggle(a: {
@@ -108,7 +108,7 @@ export class Value<Type, Store, Vault> {
Default is false */ Default is false */
immutable?: boolean immutable?: boolean
}) { }) {
return new Value<boolean, never, never>( return new Value<boolean, never>(
async () => ({ async () => ({
description: null, description: null,
warning: null, warning: null,
@@ -120,10 +120,9 @@ export class Value<Type, Store, Vault> {
boolean, boolean,
) )
} }
static dynamicToggle<Store = never, Vault = never>( static dynamicToggle<Store = never>(
a: LazyBuild< a: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -133,7 +132,7 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<boolean, Store, Vault>( return new Value<boolean, Store>(
async (options) => ({ async (options) => ({
description: null, description: null,
warning: null, warning: null,
@@ -165,7 +164,7 @@ export class Value<Type, Store, Vault> {
immutable?: boolean immutable?: boolean
generate?: null | RandomString generate?: null | RandomString
}) { }) {
return new Value<AsRequired<string, Required>, never, never>( return new Value<AsRequired<string, Required>, never>(
async () => ({ async () => ({
type: "text" as const, type: "text" as const,
description: null, description: null,
@@ -185,10 +184,9 @@ export class Value<Type, Store, Vault> {
asRequiredParser(string, a), asRequiredParser(string, a),
) )
} }
static dynamicText<Store = never, Vault = never>( static dynamicText<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -211,28 +209,25 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<string | null | undefined, Store, Vault>( return new Value<string | null | undefined, Store>(async (options) => {
async (options) => { const a = await getA(options)
const a = await getA(options) return {
return { type: "text" as const,
type: "text" as const, description: null,
description: null, warning: null,
warning: null, masked: false,
masked: false, placeholder: null,
placeholder: null, minLength: null,
minLength: null, maxLength: null,
maxLength: null, patterns: [],
patterns: [], inputmode: "text",
inputmode: "text", disabled: false,
disabled: false, immutable: false,
immutable: false, generate: a.generate ?? null,
generate: a.generate ?? null, ...a,
...a, ...requiredLikeToAbove(a.required),
...requiredLikeToAbove(a.required), }
} }, string.optional())
},
string.optional(),
)
} }
static textarea(a: { static textarea(a: {
name: string name: string
@@ -246,7 +241,7 @@ export class Value<Type, Store, Vault> {
Default is false */ Default is false */
immutable?: boolean immutable?: boolean
}) { }) {
return new Value<string, never, never>(async () => { return new Value<string, never>(async () => {
const built: ValueSpecTextarea = { const built: ValueSpecTextarea = {
description: null, description: null,
warning: null, warning: null,
@@ -261,10 +256,9 @@ export class Value<Type, Store, Vault> {
return built return built
}, string) }, string)
} }
static dynamicTextarea<Store = never, Vault = never>( static dynamicTextarea<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -277,7 +271,7 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<string, Store, Vault>(async (options) => { return new Value<string, Store>(async (options) => {
const a = await getA(options) const a = await getA(options)
return { return {
description: null, description: null,
@@ -308,7 +302,7 @@ export class Value<Type, Store, Vault> {
Default is false */ Default is false */
immutable?: boolean immutable?: boolean
}) { }) {
return new Value<AsRequired<number, Required>, never, never>( return new Value<AsRequired<number, Required>, never>(
() => ({ () => ({
type: "number" as const, type: "number" as const,
description: null, description: null,
@@ -326,10 +320,9 @@ export class Value<Type, Store, Vault> {
asRequiredParser(number, a), asRequiredParser(number, a),
) )
} }
static dynamicNumber<Store = never, Vault = never>( static dynamicNumber<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -346,26 +339,23 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<number | null | undefined, Store, Vault>( return new Value<number | null | undefined, Store>(async (options) => {
async (options) => { const a = await getA(options)
const a = await getA(options) return {
return { type: "number" as const,
type: "number" as const, description: null,
description: null, warning: null,
warning: null, min: null,
min: null, max: null,
max: null, step: null,
step: null, units: null,
units: null, placeholder: null,
placeholder: null, disabled: false,
disabled: false, immutable: false,
immutable: false, ...a,
...a, ...requiredLikeToAbove(a.required),
...requiredLikeToAbove(a.required), }
} }, number.optional())
},
number.optional(),
)
} }
static color<Required extends RequiredDefault<string>>(a: { static color<Required extends RequiredDefault<string>>(a: {
name: string name: string
@@ -376,7 +366,7 @@ export class Value<Type, Store, Vault> {
Default is false */ Default is false */
immutable?: boolean immutable?: boolean
}) { }) {
return new Value<AsRequired<string, Required>, never, never>( return new Value<AsRequired<string, Required>, never>(
() => ({ () => ({
type: "color" as const, type: "color" as const,
description: null, description: null,
@@ -391,10 +381,9 @@ export class Value<Type, Store, Vault> {
) )
} }
static dynamicColor<Store = never, Vault = never>( static dynamicColor<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -404,21 +393,18 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<string | null | undefined, Store, Vault>( return new Value<string | null | undefined, Store>(async (options) => {
async (options) => { const a = await getA(options)
const a = await getA(options) return {
return { type: "color" as const,
type: "color" as const, description: null,
description: null, warning: null,
warning: null, disabled: false,
disabled: false, immutable: false,
immutable: false, ...a,
...a, ...requiredLikeToAbove(a.required),
...requiredLikeToAbove(a.required), }
} }, string.optional())
},
string.optional(),
)
} }
static datetime<Required extends RequiredDefault<string>>(a: { static datetime<Required extends RequiredDefault<string>>(a: {
name: string name: string
@@ -433,7 +419,7 @@ export class Value<Type, Store, Vault> {
Default is false */ Default is false */
immutable?: boolean immutable?: boolean
}) { }) {
return new Value<AsRequired<string, Required>, never, never>( return new Value<AsRequired<string, Required>, never>(
() => ({ () => ({
type: "datetime" as const, type: "datetime" as const,
description: null, description: null,
@@ -450,10 +436,9 @@ export class Value<Type, Store, Vault> {
asRequiredParser(string, a), asRequiredParser(string, a),
) )
} }
static dynamicDatetime<Store = never, Vault = never>( static dynamicDatetime<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -467,24 +452,21 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<string | null | undefined, Store, Vault>( return new Value<string | null | undefined, Store>(async (options) => {
async (options) => { const a = await getA(options)
const a = await getA(options) return {
return { type: "datetime" as const,
type: "datetime" as const, description: null,
description: null, warning: null,
warning: null, inputmode: "datetime-local",
inputmode: "datetime-local", min: null,
min: null, max: null,
max: null, disabled: false,
disabled: false, immutable: false,
immutable: false, ...a,
...a, ...requiredLikeToAbove(a.required),
...requiredLikeToAbove(a.required), }
} }, string.optional())
},
string.optional(),
)
} }
static select< static select<
Required extends RequiredDefault<string>, Required extends RequiredDefault<string>,
@@ -505,7 +487,7 @@ export class Value<Type, Store, Vault> {
Default is false */ Default is false */
immutable?: boolean immutable?: boolean
}) { }) {
return new Value<AsRequired<keyof B, Required>, never, never>( return new Value<AsRequired<keyof B, Required>, never>(
() => ({ () => ({
description: null, description: null,
warning: null, warning: null,
@@ -523,10 +505,9 @@ export class Value<Type, Store, Vault> {
) as any, ) as any,
) )
} }
static dynamicSelect<Store = never, Vault = never>( static dynamicSelect<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -542,21 +523,18 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<string | null | undefined, Store, Vault>( return new Value<string | null | undefined, Store>(async (options) => {
async (options) => { const a = await getA(options)
const a = await getA(options) return {
return { description: null,
description: null, warning: null,
warning: null, type: "select" as const,
type: "select" as const, disabled: false,
disabled: false, immutable: false,
immutable: false, ...a,
...a, ...requiredLikeToAbove(a.required),
...requiredLikeToAbove(a.required), }
} }, string.optional())
},
string.optional(),
)
} }
static multiselect<Values extends Record<string, string>>(a: { static multiselect<Values extends Record<string, string>>(a: {
name: string name: string
@@ -576,7 +554,7 @@ export class Value<Type, Store, Vault> {
*/ */
disabled?: false | string | (string & keyof Values)[] disabled?: false | string | (string & keyof Values)[]
}) { }) {
return new Value<(keyof Values)[], never, never>( return new Value<(keyof Values)[], never>(
() => ({ () => ({
type: "multiselect" as const, type: "multiselect" as const,
minLength: null, minLength: null,
@@ -592,10 +570,9 @@ export class Value<Type, Store, Vault> {
), ),
) )
} }
static dynamicMultiselect<Store = never, Vault = never>( static dynamicMultiselect<Store = never>(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -613,7 +590,7 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<string[], Store, Vault>(async (options) => { return new Value<string[], Store>(async (options) => {
const a = await getA(options) const a = await getA(options)
return { return {
type: "multiselect" as const, type: "multiselect" as const,
@@ -627,15 +604,15 @@ export class Value<Type, Store, Vault> {
} }
}, arrayOf(string)) }, arrayOf(string))
} }
static object<Type extends Record<string, any>, Store, Vault>( static object<Type extends Record<string, any>, Store>(
a: { a: {
name: string name: string
description?: string | null description?: string | null
warning?: string | null warning?: string | null
}, },
spec: Config<Type, Store, Vault>, spec: Config<Type, Store>,
) { ) {
return new Value<Type, Store, Vault>(async (options) => { return new Value<Type, Store>(async (options) => {
const built = await spec.build(options as any) const built = await spec.build(options as any)
return { return {
type: "object" as const, type: "object" as const,
@@ -646,7 +623,7 @@ export class Value<Type, Store, Vault> {
} }
}, spec.validator) }, spec.validator)
} }
static file<Required extends boolean, Store, Vault>(a: { static file<Required extends boolean, Store>(a: {
name: string name: string
description?: string | null description?: string | null
warning?: string | null warning?: string | null
@@ -660,17 +637,16 @@ export class Value<Type, Store, Vault> {
...a, ...a,
} }
if (a.required) { if (a.required) {
return new Value<string, Store, Vault>(() => buildValue, string) return new Value<string, Store>(() => buildValue, string)
} }
return new Value<string | null | undefined, Store, Vault>( return new Value<string | null | undefined, Store>(
() => buildValue, () => buildValue,
string.optional(), string.optional(),
) )
} }
static dynamicFile<Required extends boolean, Store, Vault>( static dynamicFile<Required extends boolean, Store>(
a: LazyBuild< a: LazyBuild<
Store, Store,
Vault,
{ {
name: string name: string
description?: string | null description?: string | null
@@ -680,7 +656,7 @@ export class Value<Type, Store, Vault> {
} }
>, >,
) { ) {
return new Value<string | null | undefined, Store, Vault>( return new Value<string | null | undefined, Store>(
async (options) => ({ async (options) => ({
type: "file" as const, type: "file" as const,
description: null, description: null,
@@ -690,7 +666,7 @@ export class Value<Type, Store, Vault> {
string.optional(), string.optional(),
) )
} }
static union<Required extends RequiredDefault<string>, Type, Store, Vault>( static union<Required extends RequiredDefault<string>, Type, Store>(
a: { a: {
name: string name: string
description?: string | null description?: string | null
@@ -706,9 +682,9 @@ export class Value<Type, Store, Vault> {
*/ */
disabled?: false | string | string[] disabled?: false | string | string[]
}, },
aVariants: Variants<Type, Store, Vault>, aVariants: Variants<Type, Store>,
) { ) {
return new Value<AsRequired<Type, Required>, Store, Vault>( return new Value<AsRequired<Type, Required>, Store>(
async (options) => ({ async (options) => ({
type: "union" as const, type: "union" as const,
description: null, description: null,
@@ -726,18 +702,17 @@ export class Value<Type, Store, Vault> {
Required extends RequiredDefault<string>, Required extends RequiredDefault<string>,
Type extends Record<string, any>, Type extends Record<string, any>,
Store = never, Store = never,
Vault = never,
>( >(
getDisabledFn: LazyBuild<Store, Vault, string[] | false | string>, getDisabledFn: LazyBuild<Store, string[] | false | string>,
a: { a: {
name: string name: string
description?: string | null description?: string | null
warning?: string | null warning?: string | null
required: Required required: Required
}, },
aVariants: Variants<Type, Store, Vault> | Variants<Type, never, never>, aVariants: Variants<Type, Store> | Variants<Type, never>,
) { ) {
return new Value<AsRequired<Type, Required>, Store, Vault>( return new Value<AsRequired<Type, Required>, Store>(
async (options) => ({ async (options) => ({
type: "union" as const, type: "union" as const,
description: null, description: null,
@@ -755,11 +730,9 @@ export class Value<Type, Store, Vault> {
Required extends RequiredDefault<string>, Required extends RequiredDefault<string>,
Type extends Record<string, any>, Type extends Record<string, any>,
Store = never, Store = never,
Vault = never,
>( >(
getA: LazyBuild< getA: LazyBuild<
Store, Store,
Vault,
{ {
disabled: string[] | false | string disabled: string[] | false | string
name: string name: string
@@ -768,9 +741,9 @@ export class Value<Type, Store, Vault> {
required: Required required: Required
} }
>, >,
aVariants: Variants<Type, Store, Vault> | Variants<Type, never, never>, aVariants: Variants<Type, Store> | Variants<Type, never>,
) { ) {
return new Value<Type | null | undefined, Store, Vault>(async (options) => { return new Value<Type | null | undefined, Store>(async (options) => {
const newValues = await getA(options) const newValues = await getA(options)
return { return {
type: "union" as const, type: "union" as const,
@@ -784,11 +757,8 @@ export class Value<Type, Store, Vault> {
}, aVariants.validator.optional()) }, aVariants.validator.optional())
} }
static list<Type, Store, Vault>(a: List<Type, Store, Vault>) { static list<Type, Store>(a: List<Type, Store>) {
return new Value<Type, Store, Vault>( return new Value<Type, Store>((options) => a.build(options), a.validator)
(options) => a.build(options),
a.validator,
)
} }
/** /**
@@ -806,6 +776,6 @@ export class Value<Type, Store, Vault> {
``` ```
*/ */
withStore<NewStore extends Store extends never ? any : Store>() { withStore<NewStore extends Store extends never ? any : Store>() {
return this as any as Value<Type, NewStore, Vault> return this as any as Value<Type, NewStore>
} }
} }

View File

@@ -51,21 +51,20 @@ export const pruning = Value.union(
); );
``` ```
*/ */
export class Variants<Type, Store, Vault> { export class Variants<Type, Store> {
static text: any static text: any
private constructor( private constructor(
public build: LazyBuild<Store, Vault, ValueSpecUnion["variants"]>, public build: LazyBuild<Store, ValueSpecUnion["variants"]>,
public validator: Parser<unknown, Type>, public validator: Parser<unknown, Type>,
) {} ) {}
static of< static of<
VariantValues extends { VariantValues extends {
[K in string]: { [K in string]: {
name: string name: string
spec: Config<any, Store, Vault> | Config<any, never, never> spec: Config<any, Store> | Config<any, never>
} }
}, },
Store = never, Store = never,
Vault = never,
>(a: VariantValues) { >(a: VariantValues) {
const validator = anyOf( const validator = anyOf(
...Object.entries(a).map(([name, { spec }]) => ...Object.entries(a).map(([name, { spec }]) =>
@@ -82,12 +81,11 @@ export class Variants<Type, Store, Vault> {
unionSelectKey: K unionSelectKey: K
// prettier-ignore // prettier-ignore
unionValueKey: unionValueKey:
VariantValues[K]["spec"] extends (Config<infer B, Store,Vault> | Config<infer B, never, never>) ? B : VariantValues[K]["spec"] extends (Config<infer B, Store> | Config<infer B, never>) ? B :
never never
} }
}[keyof VariantValues], }[keyof VariantValues],
Store, Store
Vault
>(async (options) => { >(async (options) => {
const variants = {} as { const variants = {} as {
[K in keyof VariantValues]: { name: string; spec: InputSpec } [K in keyof VariantValues]: { name: string; spec: InputSpec }
@@ -117,6 +115,6 @@ export class Variants<Type, Store, Vault> {
``` ```
*/ */
withStore<NewStore extends Store extends never ? any : Store>() { withStore<NewStore extends Store extends never ? any : Store>() {
return this as any as Variants<Type, NewStore, Vault> return this as any as Variants<Type, NewStore>
} }
} }

View File

@@ -7,7 +7,7 @@ import { Variants } from "./builder/variants"
/** /**
* Base SMTP settings, to be used by StartOS for system wide SMTP * Base SMTP settings, to be used by StartOS for system wide SMTP
*/ */
export const customSmtp = Config.of<ConfigSpecOf<SmtpValue>, never, never>({ export const customSmtp = Config.of<ConfigSpecOf<SmtpValue>, never>({
server: Value.text({ server: Value.text({
name: "SMTP Server", name: "SMTP Server",
required: { required: {

View File

@@ -14,16 +14,15 @@ export type DependenciesReceipt = void & {
export type Save< export type Save<
Store, Store,
Vault,
A extends A extends
| Record<string, any> | Record<string, any>
| Config<Record<string, any>, any, any> | Config<Record<string, any>, any>
| Config<Record<string, never>, never, never>, | Config<Record<string, never>, never>,
Manifest extends SDKManifest, Manifest extends SDKManifest,
> = (options: { > = (options: {
effects: Effects effects: Effects
input: ExtractConfigType<A> & Record<string, any> input: ExtractConfigType<A> & Record<string, any>
utils: Utils<Store, Vault> utils: Utils<Store>
dependencies: D.ConfigDependencies<Manifest> dependencies: D.ConfigDependencies<Manifest>
}) => Promise<{ }) => Promise<{
dependenciesReceipt: DependenciesReceipt dependenciesReceipt: DependenciesReceipt
@@ -32,14 +31,13 @@ export type Save<
}> }>
export type Read< export type Read<
Store, Store,
Vault,
A extends A extends
| Record<string, any> | Record<string, any>
| Config<Record<string, any>, any, any> | Config<Record<string, any>, any>
| Config<Record<string, any>, never, never>, | Config<Record<string, any>, never>,
> = (options: { > = (options: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
}) => Promise<void | (ExtractConfigType<A> & Record<string, any>)> }) => Promise<void | (ExtractConfigType<A> & Record<string, any>)>
/** /**
* We want to setup a config export with a get and set, this * We want to setup a config export with a get and set, this
@@ -50,17 +48,16 @@ export type Read<
*/ */
export function setupConfig< export function setupConfig<
Store, Store,
Vault,
ConfigType extends ConfigType extends
| Record<string, any> | Record<string, any>
| Config<any, any, any> | Config<any, any>
| Config<any, never, never>, | Config<any, never>,
Manifest extends SDKManifest, Manifest extends SDKManifest,
Type extends Record<string, any> = ExtractConfigType<ConfigType>, Type extends Record<string, any> = ExtractConfigType<ConfigType>,
>( >(
spec: Config<Type, Store, Vault> | Config<Type, never, never>, spec: Config<Type, Store> | Config<Type, never>,
write: Save<Store, Vault, Type, Manifest>, write: Save<Store, Type, Manifest>,
read: Read<Store, Vault, Type>, read: Read<Store, Type>,
) { ) {
const validator = spec.validator const validator = spec.validator
return { return {
@@ -82,7 +79,7 @@ export function setupConfig<
} }
}) as ExpectedExports.setConfig, }) as ExpectedExports.setConfig,
getConfig: (async ({ effects }) => { getConfig: (async ({ effects }) => {
const myUtils = utils<Store, Vault>(effects) const myUtils = utils<Store>(effects)
const configValue = nullIfEmpty( const configValue = nullIfEmpty(
(await read({ effects, utils: myUtils })) || null, (await read({ effects, utils: myUtils })) || null,
) )

View File

@@ -9,7 +9,6 @@ import { deepMerge } from "../util/deepMerge"
export class DependencyConfig< export class DependencyConfig<
Store, Store,
Vault,
Input extends Record<string, any>, Input extends Record<string, any>,
RemoteConfig extends Record<string, any>, RemoteConfig extends Record<string, any>,
> { > {
@@ -18,7 +17,7 @@ export class DependencyConfig<
effects: Effects effects: Effects
localConfig: Input localConfig: Input
remoteConfig: RemoteConfig remoteConfig: RemoteConfig
utils: Utils<Store, Vault> utils: Utils<Store>
}) => Promise<void | DeepPartial<RemoteConfig>>, }) => Promise<void | DeepPartial<RemoteConfig>>,
) {} ) {}
@@ -28,7 +27,7 @@ export class DependencyConfig<
const origConfig = JSON.parse(JSON.stringify(options.localConfig)) const origConfig = JSON.parse(JSON.stringify(options.localConfig))
const newOptions = { const newOptions = {
...options, ...options,
utils: utils<Store, Vault>(options.effects), utils: utils<Store>(options.effects),
localConfig: options.localConfig as Input, localConfig: options.localConfig as Input,
remoteConfig: options.remoteConfig as RemoteConfig, remoteConfig: options.remoteConfig as RemoteConfig,
} }
@@ -49,7 +48,7 @@ export class DependencyConfig<
): ReturnType<DependencyConfigType["autoConfigure"]> { ): ReturnType<DependencyConfigType["autoConfigure"]> {
const newOptions = { const newOptions = {
...options, ...options,
utils: utils<Store, Vault>(options.effects), utils: utils<Store>(options.effects),
localConfig: options.localConfig as Input, localConfig: options.localConfig as Input,
remoteConfig: options.remoteConfig as any, remoteConfig: options.remoteConfig as any,
} }

View File

@@ -5,15 +5,13 @@ import { DependencyConfig } from "./DependencyConfig"
export function setupDependencyConfig< export function setupDependencyConfig<
Store, Store,
Vault,
Input extends Record<string, any>, Input extends Record<string, any>,
Manifest extends SDKManifest, Manifest extends SDKManifest,
>( >(
_config: Config<Input, Store, Vault> | Config<Input, never, never>, _config: Config<Input, Store> | Config<Input, never>,
autoConfigs: { autoConfigs: {
[key in keyof Manifest["dependencies"] & string]: DependencyConfig< [key in keyof Manifest["dependencies"] & string]: DependencyConfig<
Store, Store,
Vault,
Input, Input,
any any
> >

View File

@@ -2,39 +2,27 @@ import { ManifestVersion } from "../../manifest/ManifestTypes"
import { Effects } from "../../types" import { Effects } from "../../types"
import { Utils } from "../../util/utils" import { Utils } from "../../util/utils"
export class Migration<Store, Vault, Version extends ManifestVersion> { export class Migration<Stor, Version extends ManifestVersion> {
constructor( constructor(
readonly options: { readonly options: {
version: Version version: Version
up: (opts: { up: (opts: { effects: Effects; utils: Utils<Stor> }) => Promise<void>
effects: Effects down: (opts: { effects: Effects; utils: Utils<Stor> }) => Promise<void>
utils: Utils<Store, Vault>
}) => Promise<void>
down: (opts: {
effects: Effects
utils: Utils<Store, Vault>
}) => Promise<void>
}, },
) {} ) {}
static of<Store, Vault, Version extends ManifestVersion>(options: { static of<Stor, Version extends ManifestVersion>(options: {
version: Version version: Version
up: (opts: { up: (opts: { effects: Effects; utils: Utils<Stor> }) => Promise<void>
effects: Effects down: (opts: { effects: Effects; utils: Utils<Stor> }) => Promise<void>
utils: Utils<Store, Vault>
}) => Promise<void>
down: (opts: {
effects: Effects
utils: Utils<Store, Vault>
}) => Promise<void>
}) { }) {
return new Migration<Store, Vault, Version>(options) return new Migration<Stor, Version>(options)
} }
async up(opts: { effects: Effects; utils: Utils<Store, Vault> }) { async up(opts: { effects: Effects; utils: Utils<Stor> }) {
this.up(opts) this.up(opts)
} }
async down(opts: { effects: Effects; utils: Utils<Store, Vault> }) { async down(opts: { effects: Effects; utils: Utils<Stor> }) {
this.down(opts) this.down(opts)
} }
} }

View File

@@ -5,34 +5,30 @@ import { createUtils } from "../../util"
import { once } from "../../util/once" import { once } from "../../util/once"
import { Migration } from "./Migration" import { Migration } from "./Migration"
export class Migrations<Store, Vault> { export class Migrations<Store> {
private constructor( private constructor(
readonly manifest: SDKManifest, readonly manifest: SDKManifest,
readonly migrations: Array<Migration<Store, Vault, any>>, readonly migrations: Array<Migration<Store, any>>,
) {} ) {}
private sortedMigrations = once(() => { private sortedMigrations = once(() => {
const migrationsAsVersions = ( const migrationsAsVersions = (
this.migrations as Array<Migration<Store, Vault, any>> this.migrations as Array<Migration<Store, any>>
).map((x) => [EmVer.parse(x.options.version), x] as const) ).map((x) => [EmVer.parse(x.options.version), x] as const)
migrationsAsVersions.sort((a, b) => a[0].compareForSort(b[0])) migrationsAsVersions.sort((a, b) => a[0].compareForSort(b[0]))
return migrationsAsVersions return migrationsAsVersions
}) })
private currentVersion = once(() => EmVer.parse(this.manifest.version)) private currentVersion = once(() => EmVer.parse(this.manifest.version))
static of< static of<Store, Migrations extends Array<Migration<Store, any>>>(
Store, manifest: SDKManifest,
Vault, ...migrations: EnsureUniqueId<Migrations>
Migrations extends Array<Migration<Store, Vault, any>>, ) {
>(manifest: SDKManifest, ...migrations: EnsureUniqueId<Migrations>) { return new Migrations(manifest, migrations as Array<Migration<Store, any>>)
return new Migrations(
manifest,
migrations as Array<Migration<Store, Vault, any>>,
)
} }
async init({ async init({
effects, effects,
previousVersion, previousVersion,
}: Parameters<ExpectedExports.init>[0]) { }: Parameters<ExpectedExports.init>[0]) {
const utils = createUtils<Store, Vault>(effects) const utils = createUtils<Store>(effects)
if (!!previousVersion) { if (!!previousVersion) {
const previousVersionEmVer = EmVer.parse(previousVersion) const previousVersionEmVer = EmVer.parse(previousVersion)
for (const [_, migration] of this.sortedMigrations() for (const [_, migration] of this.sortedMigrations()
@@ -46,7 +42,7 @@ export class Migrations<Store, Vault> {
effects, effects,
nextVersion, nextVersion,
}: Parameters<ExpectedExports.uninit>[0]) { }: Parameters<ExpectedExports.uninit>[0]) {
const utils = createUtils<Store, Vault>(effects) const utils = createUtils<Store>(effects)
if (!!nextVersion) { if (!!nextVersion) {
const nextVersionEmVer = EmVer.parse(nextVersion) const nextVersionEmVer = EmVer.parse(nextVersion)
const reversed = [...this.sortedMigrations()].reverse() const reversed = [...this.sortedMigrations()].reverse()
@@ -61,16 +57,15 @@ export class Migrations<Store, Vault> {
export function setupMigrations< export function setupMigrations<
Store, Store,
Vault, Migrations extends Array<Migration<Store, any>>,
Migrations extends Array<Migration<Store, Vault, any>>,
>(manifest: SDKManifest, ...migrations: EnsureUniqueId<Migrations>) { >(manifest: SDKManifest, ...migrations: EnsureUniqueId<Migrations>) {
return Migrations.of<Store, Vault, Migrations>(manifest, ...migrations) return Migrations.of<Store, Migrations>(manifest, ...migrations)
} }
// prettier-ignore // prettier-ignore
export type EnsureUniqueId<A, B = A, ids = never> = export type EnsureUniqueId<A, B = A, ids = never> =
B extends [] ? A : B extends [] ? A :
B extends [Migration<any,any, infer id>, ...infer Rest] ? ( B extends [Migration<any, infer id>, ...infer Rest] ? (
id extends ids ? "One of the ids are not unique"[] : id extends ids ? "One of the ids are not unique"[] :
EnsureUniqueId<A, Rest, id | ids> EnsureUniqueId<A, Rest, id | ids>
) : "There exists a migration that is not a Migration"[] ) : "There exists a migration that is not a Migration"[]

View File

@@ -6,11 +6,11 @@ import { SetupExports } from "./setupExports"
import { Install } from "./setupInstall" import { Install } from "./setupInstall"
import { Uninstall } from "./setupUninstall" import { Uninstall } from "./setupUninstall"
export function setupInit<Store, Vault>( export function setupInit<Store>(
migrations: Migrations<Store, Vault>, migrations: Migrations<Store>,
install: Install<Store, Vault>, install: Install<Store>,
uninstall: Uninstall<Store, Vault>, uninstall: Uninstall<Store>,
setInterfaces: SetInterfaces<Store, Vault, any, any>, setInterfaces: SetInterfaces<Store, any, any>,
setupExports: SetupExports<Store>, setupExports: SetupExports<Store>,
): { ): {
init: ExpectedExports.init init: ExpectedExports.init

View File

@@ -1,13 +1,13 @@
import { Effects, ExpectedExports } from "../types" import { Effects, ExpectedExports } from "../types"
import { Utils, utils } from "../util/utils" import { Utils, utils } from "../util/utils"
export type InstallFn<Store, Vault> = (opts: { export type InstallFn<Store> = (opts: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
}) => Promise<void> }) => Promise<void>
export class Install<Store, Vault> { export class Install<Store> {
private constructor(readonly fn: InstallFn<Store, Vault>) {} private constructor(readonly fn: InstallFn<Store>) {}
static of<Store, Vault>(fn: InstallFn<Store, Vault>) { static of<Store>(fn: InstallFn<Store>) {
return new Install(fn) return new Install(fn)
} }
@@ -23,6 +23,6 @@ export class Install<Store, Vault> {
} }
} }
export function setupInstall<Store, Vault>(fn: InstallFn<Store, Vault>) { export function setupInstall<Store>(fn: InstallFn<Store>) {
return Install.of(fn) return Install.of(fn)
} }

View File

@@ -1,13 +1,13 @@
import { Effects, ExpectedExports } from "../types" import { Effects, ExpectedExports } from "../types"
import { Utils, utils } from "../util/utils" import { Utils, utils } from "../util/utils"
export type UninstallFn<Store, Vault> = (opts: { export type UninstallFn<Store> = (opts: {
effects: Effects effects: Effects
utils: Utils<Store, Vault> utils: Utils<Store>
}) => Promise<void> }) => Promise<void>
export class Uninstall<Store, Vault> { export class Uninstall<Store> {
private constructor(readonly fn: UninstallFn<Store, Vault>) {} private constructor(readonly fn: UninstallFn<Store>) {}
static of<Store, Vault>(fn: UninstallFn<Store, Vault>) { static of<Store>(fn: UninstallFn<Store>) {
return new Uninstall(fn) return new Uninstall(fn)
} }
@@ -23,6 +23,6 @@ export class Uninstall<Store, Vault> {
} }
} }
export function setupUninstall<Store, Vault>(fn: UninstallFn<Store, Vault>) { export function setupUninstall<Store>(fn: UninstallFn<Store>) {
return Uninstall.of(fn) return Uninstall.of(fn)
} }

View File

@@ -6,22 +6,20 @@ import { AddressReceipt } from "./AddressReceipt"
export type InterfacesReceipt = Array<Address[] & AddressReceipt> export type InterfacesReceipt = Array<Address[] & AddressReceipt>
export type SetInterfaces< export type SetInterfaces<
Store, Store,
Vault,
ConfigInput extends Record<string, any>, ConfigInput extends Record<string, any>,
Output extends InterfacesReceipt, Output extends InterfacesReceipt,
> = (opts: { > = (opts: {
effects: Effects effects: Effects
input: null | ConfigInput input: null | ConfigInput
utils: Utils<Store, Vault> utils: Utils<Store>
}) => Promise<Output> }) => Promise<Output>
export type SetupInterfaces = < export type SetupInterfaces = <
Store, Store,
Vault,
ConfigInput extends Record<string, any>, ConfigInput extends Record<string, any>,
Output extends InterfacesReceipt, Output extends InterfacesReceipt,
>( >(
config: Config<ConfigInput, Store, Vault>, config: Config<ConfigInput, Store>,
fn: SetInterfaces<Store, Vault, ConfigInput, Output>, fn: SetInterfaces<Store, ConfigInput, Output>,
) => SetInterfaces<Store, Vault, ConfigInput, Output> ) => SetInterfaces<Store, ConfigInput, Output>
export const NO_INTERFACE_CHANGES = [] as InterfacesReceipt export const NO_INTERFACE_CHANGES = [] as InterfacesReceipt
export const setupInterfaces: SetupInterfaces = (_config, fn) => fn export const setupInterfaces: SetupInterfaces = (_config, fn) => fn

View File

@@ -17,17 +17,17 @@ import "./Daemons"
* @param fn * @param fn
* @returns * @returns
*/ */
export const setupMain = <Store, Vault>( export const setupMain = <Store>(
fn: (o: { fn: (o: {
effects: Effects effects: Effects
started(onTerm: () => void): null started(onTerm: () => void): null
utils: Utils<Store, Vault, {}> utils: Utils<Store, {}>
}) => Promise<Daemons<any>>, }) => Promise<Daemons<any>>,
): ExpectedExports.main => { ): ExpectedExports.main => {
return async (options) => { return async (options) => {
const result = await fn({ const result = await fn({
...options, ...options,
utils: createMainUtils<Store, Vault>(options.effects), utils: createMainUtils<Store>(options.effects),
}) })
await result.build().then((x) => x.wait()) await result.build().then((x) => x.wait())
} }

View File

@@ -45,5 +45,4 @@ export const sdk = StartSdk.of()
}), }),
) )
.withStore<{ storeRoot: { storeLeaf: "value" } }>() .withStore<{ storeRoot: { storeLeaf: "value" } }>()
.withVault<{ vaultRoot: "value" }>()
.build(true) .build(true)

View File

@@ -7,9 +7,6 @@ type Store = {
someValue: "a" | "b" someValue: "a" | "b"
} }
} }
type Vault = {
hello: string
}
const todo = <A>(): A => { const todo = <A>(): A => {
throw new Error("not implemented") throw new Error("not implemented")
} }
@@ -51,10 +48,10 @@ describe("Store", () => {
path: "/config/some2Value", path: "/config/some2Value",
value: "a", value: "a",
}) })
;(await createMainUtils<Store, Vault>(todo<Effects>()) ;(await createMainUtils<Store>(todo<Effects>())
.store.getOwn("/config/someValue") .store.getOwn("/config/someValue")
.const()) satisfies string .const()) satisfies string
;(await createMainUtils<Store, Vault>(todo<Effects>()) ;(await createMainUtils<Store>(todo<Effects>())
.store.getOwn("/config") .store.getOwn("/config")
.const()) satisfies Store["config"] .const()) satisfies Store["config"]
await createMainUtils(todo<Effects>()) await createMainUtils(todo<Effects>())

View File

@@ -462,14 +462,6 @@ export type Effects = {
}): Promise<string> }): Promise<string>
stopped(packageId?: string): Promise<boolean> stopped(packageId?: string): Promise<boolean>
vault: {
list(): Promise<string[]>
get(opt: { key: string; callback: () => void }): Promise<string>
set(opt: { key: string; value: string }): Promise<void>
move(opt: { fromKey: string; toKey: string }): Promise<void>
delete(opt: { key: string }): Promise<void>
}
} }
// prettier-ignore // prettier-ignore

View File

@@ -1,44 +0,0 @@
import { Effects, EnsureStorePath } from "../types"
export class GetVault<Vault> {
constructor(readonly effects: Effects, readonly key: keyof Vault & string) {}
/**
* Returns the value of Store at the provided path. Restart the service if the value changes
*/
const() {
return this.effects.vault.get({
key: this.key,
callback: this.effects.restart,
})
}
/**
* Returns the value of Store at the provided path. Does nothing if the value changes
*/
once() {
return this.effects.vault.get({
key: this.key,
callback: () => {},
})
}
/**
* Watches the value of Store at the provided path. Takes a custom callback function to run whenever the value changes
*/
async *watch() {
while (true) {
let callback: () => void
const waitForNext = new Promise<void>((resolve) => {
callback = resolve
})
yield await this.effects.vault.get({
key: this.key,
callback: () => callback(),
})
await waitForNext
}
}
}
export function getVault<Vault>(effects: Effects, key: keyof Vault & string) {
return new GetVault<Vault>(effects, key)
}

View File

@@ -22,8 +22,8 @@ export const isKnownError = (e: unknown): e is T.KnownError =>
declare const affine: unique symbol declare const affine: unique symbol
export const createUtils = utils export const createUtils = utils
export const createMainUtils = <Store, Vault>(effects: T.Effects) => export const createMainUtils = <Store>(effects: T.Effects) =>
createUtils<Store, Vault, {}>(effects) createUtils<Store, {}>(effects)
type NeverPossible = { [affine]: string } type NeverPossible = { [affine]: string }
export type NoAny<A> = NeverPossible extends A export type NoAny<A> = NeverPossible extends A

View File

@@ -16,7 +16,6 @@ import { GetSystemSmtp } from "./GetSystemSmtp"
import { DefaultString } from "../config/configTypes" import { DefaultString } from "../config/configTypes"
import { getDefaultString } from "./getDefaultString" import { getDefaultString } from "./getDefaultString"
import { GetStore, getStore } from "../store/getStore" import { GetStore, getStore } from "../store/getStore"
import { GetVault, getVault } from "./getVault"
import { import {
MountDependenciesOut, MountDependenciesOut,
mountDependencies, mountDependencies,
@@ -62,11 +61,6 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
path: string path: string
search: Record<string, string> search: Record<string, string>
}) => NetworkInterfaceBuilder }) => NetworkInterfaceBuilder
createOrUpdateVault: (opts: {
key: keyof Vault & string
value: string | null | undefined
generator: DefaultString
}) => Promise<string>
getSystemSmtp: () => GetSystemSmtp & WrapperOverWrite getSystemSmtp: () => GetSystemSmtp & WrapperOverWrite
host: { host: {
static: (id: string) => StaticHost static: (id: string) => StaticHost
@@ -108,43 +102,14 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
value: ExtractStore<Store, Path>, value: ExtractStore<Store, Path>,
) => Promise<void> ) => Promise<void>
} }
vault: {
get: (key: keyof Vault & string) => GetVault<Vault> & WrapperOverWrite
set: (key: keyof Vault & string, value: string) => Promise<void>
}
writeFile: <A>( writeFile: <A>(
fileHelper: FileHelper<A>, fileHelper: FileHelper<A>,
data: A, data: A,
) => ReturnType<FileHelper<A>["write"]> ) => ReturnType<FileHelper<A>["write"]>
} }
export const utils = < export const utils = <Store = never, WrapperOverWrite = { const: never }>(
Store = never,
Vault = never,
WrapperOverWrite = { const: never },
>(
effects: Effects, effects: Effects,
): Utils<Store, Vault, WrapperOverWrite> => ({ ): Utils<Store, WrapperOverWrite> => ({
createOrUpdateVault: async ({
key,
value,
generator,
}: {
key: keyof Vault & string
value: string | null | undefined
generator: DefaultString
}) => {
if (value) {
await effects.vault.set({ key, value })
return value
}
const oldValue = await effects.vault.get({ key, callback: noop })
if (oldValue) {
return oldValue
}
const newValue = getDefaultString(generator)
await effects.vault.set({ key, value: newValue })
return newValue
},
createInterface: (options: { createInterface: (options: {
name: string name: string
id: string id: string
@@ -198,12 +163,7 @@ export const utils = <
}, },
checkPortListening: checkPortListening.bind(null, effects), checkPortListening: checkPortListening.bind(null, effects),
checkWebUrl: checkWebUrl.bind(null, effects), checkWebUrl: checkWebUrl.bind(null, effects),
vault: {
get: (key: keyof Vault & string) =>
getVault<Vault>(effects, key) as GetVault<Vault> & WrapperOverWrite,
set: (key: keyof Vault & string, value: string) =>
effects.vault.set({ key, value }),
},
mountDependencies: < mountDependencies: <
In extends In extends
| Record<ManifestId, Record<VolumeName, Record<NamedPath, Path>>> | Record<ManifestId, Record<VolumeName, Record<NamedPath, Path>>>