mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 10:21:55 +00:00
feat: Add vault through utils + sdk
This commit is contained in:
142
lib/StartSdk.ts
142
lib/StartSdk.ts
@@ -55,24 +55,29 @@ type AnyNeverCond<T extends any[], Then, Else> =
|
||||
T extends [any, ...infer U] ? AnyNeverCond<U,Then, Else> :
|
||||
never
|
||||
|
||||
export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
|
||||
private constructor(readonly manifest: Manifest) {}
|
||||
static of() {
|
||||
return new StartSdk<never, never>(null as never)
|
||||
return new StartSdk<never, never, never>(null as never)
|
||||
}
|
||||
withManifest<Manifest extends SDKManifest = never>(manifest: Manifest) {
|
||||
return new StartSdk<Manifest, Store>(manifest)
|
||||
return new StartSdk<Manifest, Store, Vault>(manifest)
|
||||
}
|
||||
withStore<Store extends Record<string, any>>() {
|
||||
return new StartSdk<Manifest, Store>(this.manifest)
|
||||
return new StartSdk<Manifest, Store, Vault>(this.manifest)
|
||||
}
|
||||
withVault<Vault extends Record<string, string>>() {
|
||||
return new StartSdk<Manifest, Store, Vault>(this.manifest)
|
||||
}
|
||||
|
||||
build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) {
|
||||
build(
|
||||
isReady: AnyNeverCond<[Manifest, Store, Vault], "Build not ready", true>,
|
||||
) {
|
||||
return {
|
||||
AutoConfig: <Input, NestedConfigs extends Record<string, any>>(
|
||||
configs: AutoConfigFrom<Store, Input, NestedConfigs>,
|
||||
path: keyof AutoConfigFrom<Store, Input, NestedConfigs>,
|
||||
) => new AutoConfig<Store, Input, NestedConfigs>(configs, path),
|
||||
configs: AutoConfigFrom<Store, Vault, Input, NestedConfigs>,
|
||||
path: keyof AutoConfigFrom<Store, Vault, Input, NestedConfigs>,
|
||||
) => new AutoConfig<Store, Vault, Input, NestedConfigs>(configs, path),
|
||||
Backups: {
|
||||
volumes: (...volumeNames: Array<keyof Manifest["volumes"] & string>) =>
|
||||
Backups.volumes<Manifest>(...volumeNames),
|
||||
@@ -84,29 +89,32 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
},
|
||||
Config: {
|
||||
of: <
|
||||
Spec extends Record<string, Value<any, Store> | Value<any, never>>,
|
||||
Spec extends Record<
|
||||
string,
|
||||
Value<any, Store, Vault> | Value<any, never, never>
|
||||
>,
|
||||
>(
|
||||
spec: Spec,
|
||||
) => Config.of<Spec, Store>(spec),
|
||||
) => Config.of<Spec, Store, Vault>(spec),
|
||||
},
|
||||
configConstants: { smtpConfig },
|
||||
createAction: <
|
||||
Store,
|
||||
ConfigType extends
|
||||
| Record<string, any>
|
||||
| Config<any, any>
|
||||
| Config<any, never>,
|
||||
| Config<any, any, any>
|
||||
| Config<any, never, never>,
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
>(
|
||||
metaData: Omit<ActionMetaData, "input"> & {
|
||||
input: Config<Type, Store> | Config<Type, never>
|
||||
input: Config<Type, Store, Vault> | Config<Type, never, never>
|
||||
},
|
||||
fn: (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
input: Type
|
||||
}) => Promise<ActionResult>,
|
||||
) => createAction<Store, ConfigType, Type>(metaData, fn),
|
||||
) => createAction<Store, Vault, ConfigType, Type>(metaData, fn),
|
||||
Daemons: { of: Daemons.of },
|
||||
healthCheck: {
|
||||
checkPortListening,
|
||||
@@ -128,14 +136,15 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
maxLength?: number | null
|
||||
},
|
||||
aSpec: {
|
||||
spec: Config<Type, Store>
|
||||
spec: Config<Type, Store, Vault>
|
||||
displayAs?: null | string
|
||||
uniqueBy?: null | UniqueBy
|
||||
},
|
||||
) => List.obj<Type, Store>(a, aSpec),
|
||||
) => List.obj<Type, Store, Vault>(a, aSpec),
|
||||
dynamicText: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -158,10 +167,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
}
|
||||
}
|
||||
>,
|
||||
) => List.dynamicText<Store>(getA),
|
||||
) => List.dynamicText<Store, Vault>(getA),
|
||||
dynamicNumber: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -181,30 +191,33 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
}
|
||||
}
|
||||
>,
|
||||
) => List.dynamicNumber<Store>(getA),
|
||||
) => List.dynamicNumber<Store, Vault>(getA),
|
||||
},
|
||||
Migration: {
|
||||
of: <Version extends ManifestVersion>(options: {
|
||||
version: Version
|
||||
up: (opts: { effects: Effects; utils: Utils<Store> }) => Promise<void>
|
||||
up: (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
down: (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
}) => Migration.of<Store, Version>(options),
|
||||
}) => Migration.of<Store, Vault, Version>(options),
|
||||
},
|
||||
setupActions: (...createdActions: CreatedAction<any, any>[]) =>
|
||||
setupActions<Store>(...createdActions),
|
||||
setupActions: (...createdActions: CreatedAction<any, any, any>[]) =>
|
||||
setupActions<Store, Vault>(...createdActions),
|
||||
setupAutoConfig: <
|
||||
Input extends Record<string, any>,
|
||||
NestedConfigs extends {
|
||||
[key in keyof Manifest["dependencies"]]: unknown
|
||||
},
|
||||
>(
|
||||
config: Config<Input, Store>,
|
||||
autoConfigs: AutoConfigFrom<Store, Input, NestedConfigs>,
|
||||
config: Config<Input, Store, Vault>,
|
||||
autoConfigs: AutoConfigFrom<Store, Vault, Input, NestedConfigs>,
|
||||
) =>
|
||||
setupAutoConfig<Store, Input, Manifest, NestedConfigs>(
|
||||
setupAutoConfig<Store, Vault, Input, Manifest, NestedConfigs>(
|
||||
config,
|
||||
autoConfigs,
|
||||
),
|
||||
@@ -213,31 +226,38 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
setupConfig: <
|
||||
ConfigType extends
|
||||
| Record<string, any>
|
||||
| Config<any, any>
|
||||
| Config<any, never>,
|
||||
| Config<any, any, any>
|
||||
| Config<any, never, never>,
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
>(
|
||||
spec: Config<Type, Store> | Config<Type, never>,
|
||||
write: Save<Store, Type, Manifest>,
|
||||
read: Read<Store, Type>,
|
||||
) => setupConfig<Store, ConfigType, Manifest, Type>(spec, write, read),
|
||||
spec: Config<Type, Store, Vault> | Config<Type, never, never>,
|
||||
write: Save<Store, Vault, Type, Manifest>,
|
||||
read: Read<Store, Vault, Type>,
|
||||
) =>
|
||||
setupConfig<Store, Vault, ConfigType, Manifest, Type>(
|
||||
spec,
|
||||
write,
|
||||
read,
|
||||
),
|
||||
setupInit: (
|
||||
migrations: Migrations<Store>,
|
||||
install: Install<Store>,
|
||||
uninstall: Uninstall<Store>,
|
||||
) => setupInit<Store>(migrations, install, uninstall),
|
||||
setupInstall: (fn: InstallFn<Store>) => Install.of(fn),
|
||||
migrations: Migrations<Store, Vault>,
|
||||
install: Install<Store, Vault>,
|
||||
uninstall: Uninstall<Store, Vault>,
|
||||
) => setupInit<Store, Vault>(migrations, install, uninstall),
|
||||
setupInstall: (fn: InstallFn<Store, Vault>) => Install.of(fn),
|
||||
setupMain: (
|
||||
fn: (o: {
|
||||
effects: Effects
|
||||
started(onTerm: () => void): null
|
||||
utils: Utils<Store, {}>
|
||||
utils: Utils<Store, Vault, {}>
|
||||
}) => Promise<Daemons<any>>,
|
||||
) => setupMain<Store>(fn),
|
||||
setupMigrations: <Migrations extends Array<Migration<Store, any>>>(
|
||||
) => setupMain<Store, Vault>(fn),
|
||||
setupMigrations: <Migrations extends Array<Migration<Store, Vault, any>>>(
|
||||
...migrations: EnsureUniqueId<Migrations>
|
||||
) => setupMigrations<Store, Migrations>(this.manifest, ...migrations),
|
||||
setupUninstall: (fn: UninstallFn<Store>) => setupUninstall<Store>(fn),
|
||||
) =>
|
||||
setupMigrations<Store, Vault, Migrations>(this.manifest, ...migrations),
|
||||
setupUninstall: (fn: UninstallFn<Store, Vault>) =>
|
||||
setupUninstall<Store, Vault>(fn),
|
||||
trigger: {
|
||||
defaultTrigger,
|
||||
cooldownTrigger,
|
||||
@@ -258,6 +278,7 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
dynamicToggle: (
|
||||
a: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -266,10 +287,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
disabled?: false | string
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicToggle<Store>(a),
|
||||
) => Value.dynamicToggle<Store, Vault>(a),
|
||||
dynamicText: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -287,10 +309,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
generate?: null | RandomString
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicText<Store>(getA),
|
||||
) => Value.dynamicText<Store, Vault>(getA),
|
||||
dynamicTextarea: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -303,10 +326,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
generate?: null | RandomString
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicTextarea<Store>(getA),
|
||||
) => Value.dynamicTextarea<Store, Vault>(getA),
|
||||
dynamicNumber: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -322,10 +346,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
disabled?: false | string
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicNumber<Store>(getA),
|
||||
) => Value.dynamicNumber<Store, Vault>(getA),
|
||||
dynamicColor: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -335,10 +360,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
disabled?: false | string
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicColor<Store>(getA),
|
||||
) => Value.dynamicColor<Store, Vault>(getA),
|
||||
dynamicDatetime: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -352,10 +378,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
disabled?: false | string
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicDatetime<Store>(getA),
|
||||
) => Value.dynamicDatetime<Store, Vault>(getA),
|
||||
dynamicSelect: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -365,10 +392,11 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
disabled?: false | string
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicSelect<Store>(getA),
|
||||
) => Value.dynamicSelect<Store, Vault>(getA),
|
||||
dynamicMultiselect: (
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -380,21 +408,23 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
disabled?: false | string
|
||||
}
|
||||
>,
|
||||
) => Value.dynamicMultiselect<Store>(getA),
|
||||
) => Value.dynamicMultiselect<Store, Vault>(getA),
|
||||
filteredUnion: <
|
||||
Required extends RequiredDefault<string>,
|
||||
Type extends Record<string, any>,
|
||||
>(
|
||||
getDisabledFn: LazyBuild<Store, string[]>,
|
||||
getDisabledFn: LazyBuild<Store, Vault, string[]>,
|
||||
a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
required: Required
|
||||
},
|
||||
aVariants: Variants<Type, Store> | Variants<Type, never>,
|
||||
aVariants:
|
||||
| Variants<Type, Store, Vault>
|
||||
| Variants<Type, never, never>,
|
||||
) =>
|
||||
Value.filteredUnion<Required, Type, Store>(
|
||||
Value.filteredUnion<Required, Type, Store, Vault>(
|
||||
getDisabledFn,
|
||||
a,
|
||||
aVariants,
|
||||
@@ -405,12 +435,12 @@ export class StartSdk<Manifest extends SDKManifest, Store> {
|
||||
VariantValues extends {
|
||||
[K in string]: {
|
||||
name: string
|
||||
spec: Config<any, Store>
|
||||
spec: Config<any, Store, Vault>
|
||||
}
|
||||
},
|
||||
>(
|
||||
a: VariantValues,
|
||||
) => Variants.of<VariantValues, Store>(a),
|
||||
) => Variants.of<VariantValues, Store, Vault>(a),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,45 +5,47 @@ import { Utils, utils } from "../util/utils"
|
||||
|
||||
export class CreatedAction<
|
||||
Store,
|
||||
Vault,
|
||||
ConfigType extends
|
||||
| Record<string, any>
|
||||
| Config<any, Store>
|
||||
| Config<any, never>,
|
||||
| Config<any, Store, Vault>
|
||||
| Config<any, never, never>,
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
> {
|
||||
private constructor(
|
||||
public readonly myMetaData: Omit<ActionMetaData, "input">,
|
||||
readonly fn: (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
input: Type
|
||||
}) => Promise<ActionResult>,
|
||||
readonly input: Config<Type, Store>,
|
||||
readonly input: Config<Type, Store, Vault>,
|
||||
) {}
|
||||
public validator = this.input.validator
|
||||
|
||||
static of<
|
||||
Store,
|
||||
Vault,
|
||||
ConfigType extends
|
||||
| Record<string, any>
|
||||
| Config<any, any>
|
||||
| Config<any, never>,
|
||||
| Config<any, any, any>
|
||||
| Config<any, never, never>,
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
>(
|
||||
metaData: Omit<ActionMetaData, "input"> & {
|
||||
input: Config<Type, Store> | Config<Type, never>
|
||||
input: Config<Type, Store, Vault> | Config<Type, never, never>
|
||||
},
|
||||
fn: (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
input: Type
|
||||
}) => Promise<ActionResult>,
|
||||
) {
|
||||
const { input, ...rest } = metaData
|
||||
return new CreatedAction<Store, ConfigType, Type>(
|
||||
return new CreatedAction<Store, Vault, ConfigType, Type>(
|
||||
rest,
|
||||
fn,
|
||||
input as Config<Type, Store>,
|
||||
input as Config<Type, Store, Vault>,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -65,7 +67,7 @@ export class CreatedAction<
|
||||
|
||||
async actionMetaData(options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
}): Promise<ActionMetaData> {
|
||||
return {
|
||||
...this.myMetaData,
|
||||
|
||||
@@ -3,11 +3,11 @@ import { createUtils } from "../util"
|
||||
import { once } from "../util/once"
|
||||
import { CreatedAction } from "./createAction"
|
||||
|
||||
export function setupActions<Store>(
|
||||
...createdActions: CreatedAction<any, any>[]
|
||||
export function setupActions<Store, Vault>(
|
||||
...createdActions: CreatedAction<Store, Vault, any>[]
|
||||
) {
|
||||
const myActions = once(() => {
|
||||
const actions: Record<string, CreatedAction<any, any>> = {}
|
||||
const actions: Record<string, CreatedAction<Store, Vault, any>> = {}
|
||||
for (const action of createdActions) {
|
||||
actions[action.myMetaData.id] = action
|
||||
}
|
||||
@@ -18,7 +18,7 @@ export function setupActions<Store>(
|
||||
return myActions()
|
||||
},
|
||||
async actionsMetaData({ effects }: { effects: Effects }) {
|
||||
const utils = createUtils<Store>(effects)
|
||||
const utils = createUtils<Store, Vault>(effects)
|
||||
return Promise.all(
|
||||
createdActions.map((x) => x.actionMetaData({ effects, utils })),
|
||||
)
|
||||
|
||||
@@ -6,27 +6,29 @@ import { Config } from "../config/builder/config"
|
||||
|
||||
export type AutoConfigFrom<
|
||||
Store,
|
||||
Vault,
|
||||
Input,
|
||||
NestedConfigs extends Record<string, any>,
|
||||
> = {
|
||||
[key in keyof NestedConfigs & string]: {
|
||||
serviceConfig: Config<NestedConfigs[key], any>
|
||||
serviceConfig: Config<NestedConfigs[key], Store, Vault>
|
||||
autoConfig: (options: {
|
||||
effects: Effects
|
||||
localConfig: Input
|
||||
remoteConfig: NestedConfigs[key]
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void | DeepPartial<NestedConfigs[key]>>
|
||||
}
|
||||
}
|
||||
export class AutoConfig<
|
||||
Store,
|
||||
Vault,
|
||||
Input,
|
||||
NestedConfigs extends Record<string, any>,
|
||||
> {
|
||||
constructor(
|
||||
readonly configs: AutoConfigFrom<Store, Input, NestedConfigs>,
|
||||
readonly path: keyof AutoConfigFrom<Store, Input, NestedConfigs>,
|
||||
readonly configs: AutoConfigFrom<Store, Vault, Input, NestedConfigs>,
|
||||
readonly path: keyof AutoConfigFrom<Store, Vault, Input, NestedConfigs>,
|
||||
) {}
|
||||
|
||||
async check(
|
||||
@@ -35,7 +37,7 @@ export class AutoConfig<
|
||||
const origConfig = JSON.parse(JSON.stringify(options.localConfig))
|
||||
const newOptions = {
|
||||
...options,
|
||||
utils: utils<Store>(options.effects),
|
||||
utils: utils<Store, Vault>(options.effects),
|
||||
localConfig: options.localConfig as Input,
|
||||
remoteConfig: options.remoteConfig as any,
|
||||
}
|
||||
@@ -56,7 +58,7 @@ export class AutoConfig<
|
||||
): ReturnType<AutoConfigure["autoConfigure"]> {
|
||||
const newOptions = {
|
||||
...options,
|
||||
utils: utils<Store>(options.effects),
|
||||
utils: utils<Store, Vault>(options.effects),
|
||||
localConfig: options.localConfig as Input,
|
||||
remoteConfig: options.remoteConfig as any,
|
||||
}
|
||||
|
||||
@@ -4,22 +4,24 @@ import { AutoConfig, AutoConfigFrom } from "./AutoConfig"
|
||||
|
||||
export function setupAutoConfig<
|
||||
Store,
|
||||
Vault,
|
||||
Input extends Record<string, any>,
|
||||
Manifest extends SDKManifest,
|
||||
NestedConfigs extends {
|
||||
[key in keyof Manifest["dependencies"]]: unknown
|
||||
},
|
||||
>(
|
||||
config: Config<Input, Store>,
|
||||
autoConfigs: AutoConfigFrom<Store, Input, NestedConfigs>,
|
||||
_config: Config<Input, Store, Vault>,
|
||||
autoConfigs: AutoConfigFrom<Store, Vault, Input, NestedConfigs>,
|
||||
) {
|
||||
type C = typeof autoConfigs
|
||||
const answer = { ...autoConfigs } as unknown as {
|
||||
[k in keyof C]: AutoConfig<Store, Input, NestedConfigs>
|
||||
[k in keyof C]: AutoConfig<Store, Vault, Input, NestedConfigs>
|
||||
}
|
||||
for (const key in autoConfigs) {
|
||||
answer[key as keyof typeof autoConfigs] = new AutoConfig<
|
||||
Store,
|
||||
Vault,
|
||||
Input,
|
||||
NestedConfigs
|
||||
>(autoConfigs, key as keyof typeof autoConfigs)
|
||||
|
||||
@@ -5,24 +5,28 @@ import { _ } from "../../util"
|
||||
import { Effects } from "../../types"
|
||||
import { Parser, object } from "ts-matches"
|
||||
|
||||
export type LazyBuildOptions<Store> = {
|
||||
export type LazyBuildOptions<Store, Vault> = {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
}
|
||||
export type LazyBuild<Store, ExpectedOut> = (
|
||||
options: LazyBuildOptions<Store>,
|
||||
export type LazyBuild<Store, Vault, ExpectedOut> = (
|
||||
options: LazyBuildOptions<Store, Vault>,
|
||||
) => Promise<ExpectedOut> | ExpectedOut
|
||||
|
||||
// prettier-ignore
|
||||
export type ExtractConfigType<A extends Record<string, any> | Config<Record<string, any>, any> | Config<Record<string, any>, never>> =
|
||||
A extends Config<infer B, any> | Config<infer B, never> ? B :
|
||||
export type ExtractConfigType<A extends Record<string, any> | Config<Record<string, any>, any, any> | Config<Record<string, any>, never, never>> =
|
||||
A extends Config<infer B, any, any> | Config<infer B, never, never> ? B :
|
||||
A
|
||||
|
||||
export type ConfigSpecOf<A extends Record<string, any>, Store = never> = {
|
||||
[K in keyof A]: Value<A[K], Store>
|
||||
export type ConfigSpecOf<
|
||||
A extends Record<string, any>,
|
||||
Store = never,
|
||||
Vault = never,
|
||||
> = {
|
||||
[K in keyof A]: Value<A[K], Store, Vault>
|
||||
}
|
||||
|
||||
export type MaybeLazyValues<A> = LazyBuild<any, A> | A
|
||||
export type MaybeLazyValues<A> = LazyBuild<any, any, A> | A
|
||||
/**
|
||||
* Configs are the specs that are used by the os configuration form for this service.
|
||||
* Here is an example of a simple configuration
|
||||
@@ -79,14 +83,16 @@ export const addNodesSpec = Config.of({ hostname: hostname, port: port });
|
||||
|
||||
```
|
||||
*/
|
||||
export class Config<Type extends Record<string, any>, Store> {
|
||||
export class Config<Type extends Record<string, any>, Store, Vault> {
|
||||
private constructor(
|
||||
private readonly spec: {
|
||||
[K in keyof Type]: Value<Type[K], Store> | Value<Type[K], never>
|
||||
[K in keyof Type]:
|
||||
| Value<Type[K], Store, Vault>
|
||||
| Value<Type[K], never, never>
|
||||
},
|
||||
public validator: Parser<unknown, Type>,
|
||||
) {}
|
||||
async build(options: LazyBuildOptions<Store>) {
|
||||
async build(options: LazyBuildOptions<Store, Vault>) {
|
||||
const answer = {} as {
|
||||
[K in keyof Type]: ValueSpec
|
||||
}
|
||||
@@ -97,8 +103,12 @@ export class Config<Type extends Record<string, any>, Store> {
|
||||
}
|
||||
|
||||
static of<
|
||||
Spec extends Record<string, Value<any, Store> | Value<any, never>>,
|
||||
Spec extends Record<
|
||||
string,
|
||||
Value<any, Store, Vault> | Value<any, never, never>
|
||||
>,
|
||||
Store,
|
||||
Vault,
|
||||
>(spec: Spec) {
|
||||
const validatorObj = {} as {
|
||||
[K in keyof Spec]: Parser<unknown, any>
|
||||
@@ -110,12 +120,13 @@ export class Config<Type extends Record<string, any>, Store> {
|
||||
return new Config<
|
||||
{
|
||||
[K in keyof Spec]: Spec[K] extends
|
||||
| Value<infer T, Store>
|
||||
| Value<infer T, never>
|
||||
| Value<infer T, Store, Vault>
|
||||
| Value<infer T, never, never>
|
||||
? T
|
||||
: never
|
||||
},
|
||||
Store
|
||||
Store,
|
||||
Vault
|
||||
>(spec, validator as any)
|
||||
}
|
||||
|
||||
@@ -134,6 +145,6 @@ export class Config<Type extends Record<string, any>, Store> {
|
||||
```
|
||||
*/
|
||||
withStore<NewStore extends Store extends never ? any : Store>() {
|
||||
return this as any as Config<Type, NewStore>
|
||||
return this as any as Config<Type, NewStore, Vault>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,9 +22,9 @@ export const authorizationList = List.string({
|
||||
export const auth = Value.list(authorizationList);
|
||||
```
|
||||
*/
|
||||
export class List<Type, Store> {
|
||||
export class List<Type, Store, Vault> {
|
||||
private constructor(
|
||||
public build: LazyBuild<Store, ValueSpecList>,
|
||||
public build: LazyBuild<Store, Vault, ValueSpecList>,
|
||||
public validator: Parser<unknown, Type>,
|
||||
) {}
|
||||
static text(
|
||||
@@ -49,7 +49,7 @@ export class List<Type, Store> {
|
||||
generate?: null | RandomString
|
||||
},
|
||||
) {
|
||||
return new List<string[], never>(() => {
|
||||
return new List<string[], never, never>(() => {
|
||||
const spec = {
|
||||
type: "text" as const,
|
||||
placeholder: null,
|
||||
@@ -73,9 +73,10 @@ export class List<Type, Store> {
|
||||
} satisfies ValueSpecListOf<"text">
|
||||
}, arrayOf(string))
|
||||
}
|
||||
static dynamicText<Store = never>(
|
||||
static dynamicText<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -99,7 +100,7 @@ export class List<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new List<string[], Store>(async (options) => {
|
||||
return new List<string[], Store, Vault>(async (options) => {
|
||||
const { spec: aSpec, ...a } = await getA(options)
|
||||
const spec = {
|
||||
type: "text" as const,
|
||||
@@ -143,7 +144,7 @@ export class List<Type, Store> {
|
||||
placeholder?: string | null
|
||||
},
|
||||
) {
|
||||
return new List<number[], never>(() => {
|
||||
return new List<number[], never, never>(() => {
|
||||
const spec = {
|
||||
type: "number" as const,
|
||||
placeholder: null,
|
||||
@@ -166,9 +167,10 @@ export class List<Type, Store> {
|
||||
} satisfies ValueSpecListOf<"number">
|
||||
}, arrayOf(number))
|
||||
}
|
||||
static dynamicNumber<Store = never>(
|
||||
static dynamicNumber<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -189,7 +191,7 @@ export class List<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new List<number[], Store>(async (options) => {
|
||||
return new List<number[], Store, Vault>(async (options) => {
|
||||
const { spec: aSpec, ...a } = await getA(options)
|
||||
const spec = {
|
||||
type: "number" as const,
|
||||
@@ -213,7 +215,7 @@ export class List<Type, Store> {
|
||||
}
|
||||
}, arrayOf(number))
|
||||
}
|
||||
static obj<Type extends Record<string, any>, Store>(
|
||||
static obj<Type extends Record<string, any>, Store, Vault>(
|
||||
a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -224,12 +226,12 @@ export class List<Type, Store> {
|
||||
maxLength?: number | null
|
||||
},
|
||||
aSpec: {
|
||||
spec: Config<Type, Store>
|
||||
spec: Config<Type, Store, Vault>
|
||||
displayAs?: null | string
|
||||
uniqueBy?: null | UniqueBy
|
||||
},
|
||||
) {
|
||||
return new List<Type[], Store>(async (options) => {
|
||||
return new List<Type[], Store, Vault>(async (options) => {
|
||||
const { spec: previousSpecSpec, ...restSpec } = aSpec
|
||||
const specSpec = await previousSpecSpec.build(options)
|
||||
const spec = {
|
||||
@@ -271,6 +273,6 @@ export class List<Type, Store> {
|
||||
```
|
||||
*/
|
||||
withStore<NewStore extends Store extends never ? any : Store>() {
|
||||
return this as any as List<Type, NewStore>
|
||||
return this as any as List<Type, NewStore, Vault>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,9 +94,9 @@ const username = Value.string({
|
||||
});
|
||||
```
|
||||
*/
|
||||
export class Value<Type, Store> {
|
||||
export class Value<Type, Store, Vault> {
|
||||
protected constructor(
|
||||
public build: LazyBuild<Store, ValueSpec>,
|
||||
public build: LazyBuild<Store, Vault, ValueSpec>,
|
||||
public validator: Parser<unknown, Type>,
|
||||
) {}
|
||||
static toggle(a: {
|
||||
@@ -108,7 +108,7 @@ export class Value<Type, Store> {
|
||||
Default is false */
|
||||
immutable?: boolean
|
||||
}) {
|
||||
return new Value<boolean, never>(
|
||||
return new Value<boolean, never, never>(
|
||||
async () => ({
|
||||
description: null,
|
||||
warning: null,
|
||||
@@ -120,9 +120,10 @@ export class Value<Type, Store> {
|
||||
boolean,
|
||||
)
|
||||
}
|
||||
static dynamicToggle<Store = never>(
|
||||
static dynamicToggle<Store = never, Vault = never>(
|
||||
a: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -132,7 +133,7 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<boolean, Store>(
|
||||
return new Value<boolean, Store, Vault>(
|
||||
async (options) => ({
|
||||
description: null,
|
||||
warning: null,
|
||||
@@ -163,7 +164,7 @@ export class Value<Type, Store> {
|
||||
immutable?: boolean
|
||||
generate?: null | RandomString
|
||||
}) {
|
||||
return new Value<AsRequired<string, Required>, never>(
|
||||
return new Value<AsRequired<string, Required>, never, never>(
|
||||
async () => ({
|
||||
type: "text" as const,
|
||||
description: null,
|
||||
@@ -183,9 +184,10 @@ export class Value<Type, Store> {
|
||||
asRequiredParser(string, a),
|
||||
)
|
||||
}
|
||||
static dynamicText<Store = never>(
|
||||
static dynamicText<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -204,25 +206,28 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<string | null | undefined, Store>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "text" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
masked: false,
|
||||
placeholder: null,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
patterns: [],
|
||||
inputmode: "text",
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
generate: a.generate ?? null,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
}, string.optional())
|
||||
return new Value<string | null | undefined, Store, Vault>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "text" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
masked: false,
|
||||
placeholder: null,
|
||||
minLength: null,
|
||||
maxLength: null,
|
||||
patterns: [],
|
||||
inputmode: "text",
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
generate: a.generate ?? null,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
},
|
||||
string.optional(),
|
||||
)
|
||||
}
|
||||
static textarea(a: {
|
||||
name: string
|
||||
@@ -237,7 +242,7 @@ export class Value<Type, Store> {
|
||||
immutable?: boolean
|
||||
generate?: null | RandomString
|
||||
}) {
|
||||
return new Value<string, never>(
|
||||
return new Value<string, never, never>(
|
||||
async () =>
|
||||
({
|
||||
description: null,
|
||||
@@ -254,9 +259,10 @@ export class Value<Type, Store> {
|
||||
string,
|
||||
)
|
||||
}
|
||||
static dynamicTextarea<Store = never>(
|
||||
static dynamicTextarea<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -270,7 +276,7 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<string, Store>(async (options) => {
|
||||
return new Value<string, Store, Vault>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
description: null,
|
||||
@@ -302,7 +308,7 @@ export class Value<Type, Store> {
|
||||
Default is false */
|
||||
immutable?: boolean
|
||||
}) {
|
||||
return new Value<AsRequired<number, Required>, never>(
|
||||
return new Value<AsRequired<number, Required>, never, never>(
|
||||
() => ({
|
||||
type: "number" as const,
|
||||
description: null,
|
||||
@@ -320,9 +326,10 @@ export class Value<Type, Store> {
|
||||
asRequiredParser(number, a),
|
||||
)
|
||||
}
|
||||
static dynamicNumber<Store = never>(
|
||||
static dynamicNumber<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -339,23 +346,26 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<number | null | undefined, Store>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "number" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
min: null,
|
||||
max: null,
|
||||
step: null,
|
||||
units: null,
|
||||
placeholder: null,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
}, number.optional())
|
||||
return new Value<number | null | undefined, Store, Vault>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "number" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
min: null,
|
||||
max: null,
|
||||
step: null,
|
||||
units: null,
|
||||
placeholder: null,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
},
|
||||
number.optional(),
|
||||
)
|
||||
}
|
||||
static color<Required extends RequiredDefault<string>>(a: {
|
||||
name: string
|
||||
@@ -366,7 +376,7 @@ export class Value<Type, Store> {
|
||||
Default is false */
|
||||
immutable?: boolean
|
||||
}) {
|
||||
return new Value<AsRequired<string, Required>, never>(
|
||||
return new Value<AsRequired<string, Required>, never, never>(
|
||||
() => ({
|
||||
type: "color" as const,
|
||||
description: null,
|
||||
@@ -381,9 +391,10 @@ export class Value<Type, Store> {
|
||||
)
|
||||
}
|
||||
|
||||
static dynamicColor<Store = never>(
|
||||
static dynamicColor<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -394,18 +405,21 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<string | null | undefined, Store>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "color" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
}, string.optional())
|
||||
return new Value<string | null | undefined, Store, Vault>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "color" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
},
|
||||
string.optional(),
|
||||
)
|
||||
}
|
||||
static datetime<Required extends RequiredDefault<string>>(a: {
|
||||
name: string
|
||||
@@ -421,7 +435,7 @@ export class Value<Type, Store> {
|
||||
Default is false */
|
||||
immutable?: boolean
|
||||
}) {
|
||||
return new Value<AsRequired<string, Required>, never>(
|
||||
return new Value<AsRequired<string, Required>, never, never>(
|
||||
() => ({
|
||||
type: "datetime" as const,
|
||||
description: null,
|
||||
@@ -438,9 +452,10 @@ export class Value<Type, Store> {
|
||||
asRequiredParser(string, a),
|
||||
)
|
||||
}
|
||||
static dynamicDatetime<Store = never>(
|
||||
static dynamicDatetime<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -455,22 +470,25 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<string | null | undefined, Store>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "datetime" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
inputmode: "datetime-local",
|
||||
min: null,
|
||||
max: null,
|
||||
step: null,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
}, string.optional())
|
||||
return new Value<string | null | undefined, Store, Vault>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "datetime" as const,
|
||||
description: null,
|
||||
warning: null,
|
||||
inputmode: "datetime-local",
|
||||
min: null,
|
||||
max: null,
|
||||
step: null,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
},
|
||||
string.optional(),
|
||||
)
|
||||
}
|
||||
static select<
|
||||
Required extends RequiredDefault<string>,
|
||||
@@ -485,7 +503,7 @@ export class Value<Type, Store> {
|
||||
Default is false */
|
||||
immutable?: boolean
|
||||
}) {
|
||||
return new Value<AsRequired<keyof B, Required>, never>(
|
||||
return new Value<AsRequired<keyof B, Required>, never, never>(
|
||||
() => ({
|
||||
description: null,
|
||||
warning: null,
|
||||
@@ -503,9 +521,10 @@ export class Value<Type, Store> {
|
||||
) as any,
|
||||
)
|
||||
}
|
||||
static dynamicSelect<Store = never>(
|
||||
static dynamicSelect<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -516,18 +535,21 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<string | null | undefined, Store>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: "select" as const,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
}, string.optional())
|
||||
return new Value<string | null | undefined, Store, Vault>(
|
||||
async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
description: null,
|
||||
warning: null,
|
||||
type: "select" as const,
|
||||
disabled: false,
|
||||
immutable: false,
|
||||
...a,
|
||||
...requiredLikeToAbove(a.required),
|
||||
}
|
||||
},
|
||||
string.optional(),
|
||||
)
|
||||
}
|
||||
static multiselect<Values extends Record<string, string>>(a: {
|
||||
name: string
|
||||
@@ -541,7 +563,7 @@ export class Value<Type, Store> {
|
||||
Default is false */
|
||||
immutable?: boolean
|
||||
}) {
|
||||
return new Value<(keyof Values)[], never>(
|
||||
return new Value<(keyof Values)[], never, never>(
|
||||
() => ({
|
||||
type: "multiselect" as const,
|
||||
minLength: null,
|
||||
@@ -557,9 +579,10 @@ export class Value<Type, Store> {
|
||||
),
|
||||
)
|
||||
}
|
||||
static dynamicMultiselect<Store = never>(
|
||||
static dynamicMultiselect<Store = never, Vault = never>(
|
||||
getA: LazyBuild<
|
||||
Store,
|
||||
Vault,
|
||||
{
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -572,7 +595,7 @@ export class Value<Type, Store> {
|
||||
}
|
||||
>,
|
||||
) {
|
||||
return new Value<string[], Store>(async (options) => {
|
||||
return new Value<string[], Store, Vault>(async (options) => {
|
||||
const a = await getA(options)
|
||||
return {
|
||||
type: "multiselect" as const,
|
||||
@@ -586,15 +609,15 @@ export class Value<Type, Store> {
|
||||
}
|
||||
}, arrayOf(string))
|
||||
}
|
||||
static object<Type extends Record<string, any>, Store>(
|
||||
static object<Type extends Record<string, any>, Store, Vault>(
|
||||
a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
},
|
||||
previousSpec: Config<Type, Store>,
|
||||
previousSpec: Config<Type, Store, Vault>,
|
||||
) {
|
||||
return new Value<Type, Store>(async (options) => {
|
||||
return new Value<Type, Store, Vault>(async (options) => {
|
||||
const spec = await previousSpec.build(options as any)
|
||||
return {
|
||||
type: "object" as const,
|
||||
@@ -605,7 +628,7 @@ export class Value<Type, Store> {
|
||||
}
|
||||
}, previousSpec.validator)
|
||||
}
|
||||
static union<Required extends RequiredDefault<string>, Type, Store>(
|
||||
static union<Required extends RequiredDefault<string>, Type, Store, Vault>(
|
||||
a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
@@ -615,9 +638,9 @@ export class Value<Type, Store> {
|
||||
Default is false */
|
||||
immutable?: boolean
|
||||
},
|
||||
aVariants: Variants<Type, Store>,
|
||||
aVariants: Variants<Type, Store, Vault>,
|
||||
) {
|
||||
return new Value<AsRequired<Type, Required>, Store>(
|
||||
return new Value<AsRequired<Type, Required>, Store, Vault>(
|
||||
async (options) => ({
|
||||
type: "union" as const,
|
||||
description: null,
|
||||
@@ -634,17 +657,18 @@ export class Value<Type, Store> {
|
||||
Required extends RequiredDefault<string>,
|
||||
Type extends Record<string, any>,
|
||||
Store = never,
|
||||
Vault = never,
|
||||
>(
|
||||
getDisabledFn: LazyBuild<Store, string[]>,
|
||||
getDisabledFn: LazyBuild<Store, Vault, string[]>,
|
||||
a: {
|
||||
name: string
|
||||
description?: string | null
|
||||
warning?: string | null
|
||||
required: Required
|
||||
},
|
||||
aVariants: Variants<Type, Store> | Variants<Type, never>,
|
||||
aVariants: Variants<Type, Store, Vault> | Variants<Type, never, never>,
|
||||
) {
|
||||
return new Value<AsRequired<Type, Required>, Store>(
|
||||
return new Value<AsRequired<Type, Required>, Store, Vault>(
|
||||
async (options) => ({
|
||||
type: "union" as const,
|
||||
description: null,
|
||||
@@ -659,8 +683,11 @@ export class Value<Type, Store> {
|
||||
)
|
||||
}
|
||||
|
||||
static list<Type, Store>(a: List<Type, Store>) {
|
||||
return new Value<Type, Store>((options) => a.build(options), a.validator)
|
||||
static list<Type, Store, Vault>(a: List<Type, Store, Vault>) {
|
||||
return new Value<Type, Store, Vault>(
|
||||
(options) => a.build(options),
|
||||
a.validator,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -678,6 +705,6 @@ export class Value<Type, Store> {
|
||||
```
|
||||
*/
|
||||
withStore<NewStore extends Store extends never ? any : Store>() {
|
||||
return this as any as Value<Type, NewStore>
|
||||
return this as any as Value<Type, NewStore, Vault>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,20 +51,21 @@ export const pruning = Value.union(
|
||||
);
|
||||
```
|
||||
*/
|
||||
export class Variants<Type, Store> {
|
||||
export class Variants<Type, Store, Vault> {
|
||||
static text: any
|
||||
private constructor(
|
||||
public build: LazyBuild<Store, ValueSpecUnion["variants"]>,
|
||||
public build: LazyBuild<Store, Vault, ValueSpecUnion["variants"]>,
|
||||
public validator: Parser<unknown, Type>,
|
||||
) {}
|
||||
static of<
|
||||
VariantValues extends {
|
||||
[K in string]: {
|
||||
name: string
|
||||
spec: Config<any, Store> | Config<any, never>
|
||||
spec: Config<any, Store, Vault> | Config<any, never, never>
|
||||
}
|
||||
},
|
||||
Store,
|
||||
Vault,
|
||||
>(a: VariantValues) {
|
||||
const validator = anyOf(
|
||||
...Object.entries(a).map(([name, { spec }]) =>
|
||||
@@ -81,11 +82,12 @@ export class Variants<Type, Store> {
|
||||
unionSelectKey: K
|
||||
// prettier-ignore
|
||||
unionValueKey:
|
||||
VariantValues[K]["spec"] extends (Config<infer B, Store> | Config<infer B, never>) ? B :
|
||||
VariantValues[K]["spec"] extends (Config<infer B, Store,Vault> | Config<infer B, never, never>) ? B :
|
||||
never
|
||||
}
|
||||
}[keyof VariantValues],
|
||||
Store
|
||||
Store,
|
||||
Vault
|
||||
>(async (options) => {
|
||||
const variants = {} as {
|
||||
[K in keyof VariantValues]: { name: string; spec: InputSpec }
|
||||
@@ -115,6 +117,6 @@ export class Variants<Type, Store> {
|
||||
```
|
||||
*/
|
||||
withStore<NewStore extends Store extends never ? any : Store>() {
|
||||
return this as any as Variants<Type, NewStore>
|
||||
return this as any as Variants<Type, NewStore, Vault>
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export const smtpConfig = Value.filteredUnion(
|
||||
system: { name: "System Credentials", spec: Config.of({}) },
|
||||
custom: {
|
||||
name: "Custom Credentials",
|
||||
spec: Config.of<ConfigSpecOf<SmtpValue>, never>({
|
||||
spec: Config.of<ConfigSpecOf<SmtpValue>, never, never>({
|
||||
server: Value.text({
|
||||
name: "SMTP Server",
|
||||
required: {
|
||||
|
||||
@@ -12,15 +12,16 @@ export type DependenciesReceipt = void & {
|
||||
|
||||
export type Save<
|
||||
Store,
|
||||
Vault,
|
||||
A extends
|
||||
| Record<string, any>
|
||||
| Config<Record<string, any>, any>
|
||||
| Config<Record<string, never>, never>,
|
||||
| Config<Record<string, any>, any, any>
|
||||
| Config<Record<string, never>, never, never>,
|
||||
Manifest extends SDKManifest,
|
||||
> = (options: {
|
||||
effects: Effects
|
||||
input: ExtractConfigType<A> & Record<string, any>
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
dependencies: D.ConfigDependencies<Manifest>
|
||||
}) => Promise<{
|
||||
dependenciesReceipt: DependenciesReceipt
|
||||
@@ -28,13 +29,14 @@ export type Save<
|
||||
}>
|
||||
export type Read<
|
||||
Store,
|
||||
Vault,
|
||||
A extends
|
||||
| Record<string, any>
|
||||
| Config<Record<string, any>, any>
|
||||
| Config<Record<string, any>, never>,
|
||||
| Config<Record<string, any>, any, any>
|
||||
| Config<Record<string, any>, never, never>,
|
||||
> = (options: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void | (ExtractConfigType<A> & Record<string, any>)>
|
||||
/**
|
||||
* We want to setup a config export with a get and set, this
|
||||
@@ -45,16 +47,17 @@ export type Read<
|
||||
*/
|
||||
export function setupConfig<
|
||||
Store,
|
||||
Vault,
|
||||
ConfigType extends
|
||||
| Record<string, any>
|
||||
| Config<any, any>
|
||||
| Config<any, never>,
|
||||
| Config<any, any, any>
|
||||
| Config<any, never, never>,
|
||||
Manifest extends SDKManifest,
|
||||
Type extends Record<string, any> = ExtractConfigType<ConfigType>,
|
||||
>(
|
||||
spec: Config<Type, Store> | Config<Type, never>,
|
||||
write: Save<Store, Type, Manifest>,
|
||||
read: Read<Store, Type>,
|
||||
spec: Config<Type, Store, Vault> | Config<Type, never, never>,
|
||||
write: Save<Store, Vault, Type, Manifest>,
|
||||
read: Read<Store, Vault, Type>,
|
||||
) {
|
||||
const validator = spec.validator
|
||||
return {
|
||||
@@ -74,7 +77,7 @@ export function setupConfig<
|
||||
}
|
||||
}) as ExpectedExports.setConfig,
|
||||
getConfig: (async ({ effects }) => {
|
||||
const myUtils = utils<Store>(effects)
|
||||
const myUtils = utils<Store, Vault>(effects)
|
||||
const configValue = nullIfEmpty(
|
||||
(await read({ effects, utils: myUtils })) || null,
|
||||
)
|
||||
|
||||
@@ -2,27 +2,39 @@ import { ManifestVersion } from "../../manifest/ManifestTypes"
|
||||
import { Effects } from "../../types"
|
||||
import { Utils } from "../../util/utils"
|
||||
|
||||
export class Migration<Store, Version extends ManifestVersion> {
|
||||
export class Migration<Store, Vault, Version extends ManifestVersion> {
|
||||
constructor(
|
||||
readonly options: {
|
||||
version: Version
|
||||
up: (opts: { effects: Effects; utils: Utils<Store> }) => Promise<void>
|
||||
down: (opts: { effects: Effects; utils: Utils<Store> }) => Promise<void>
|
||||
up: (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
down: (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
},
|
||||
) {}
|
||||
static of<Store, Version extends ManifestVersion>(options: {
|
||||
static of<Store, Vault, Version extends ManifestVersion>(options: {
|
||||
version: Version
|
||||
up: (opts: { effects: Effects; utils: Utils<Store> }) => Promise<void>
|
||||
down: (opts: { effects: Effects; utils: Utils<Store> }) => Promise<void>
|
||||
up: (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
down: (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
}) {
|
||||
return new Migration<Store, Version>(options)
|
||||
return new Migration<Store, Vault, Version>(options)
|
||||
}
|
||||
|
||||
async up(opts: { effects: Effects; utils: Utils<Store> }) {
|
||||
async up(opts: { effects: Effects; utils: Utils<Store, Vault> }) {
|
||||
this.up(opts)
|
||||
}
|
||||
|
||||
async down(opts: { effects: Effects; utils: Utils<Store> }) {
|
||||
async down(opts: { effects: Effects; utils: Utils<Store, Vault> }) {
|
||||
this.down(opts)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { setupActions } from "../../actions/setupActions"
|
||||
import { EmVer } from "../../emverLite/mod"
|
||||
import { SDKManifest } from "../../manifest/ManifestTypes"
|
||||
import { ExpectedExports } from "../../types"
|
||||
@@ -6,30 +5,34 @@ import { createUtils } from "../../util"
|
||||
import { once } from "../../util/once"
|
||||
import { Migration } from "./Migration"
|
||||
|
||||
export class Migrations<Store> {
|
||||
export class Migrations<Store, Vault> {
|
||||
private constructor(
|
||||
readonly manifest: SDKManifest,
|
||||
readonly migrations: Array<Migration<Store, any>>,
|
||||
readonly migrations: Array<Migration<Store, Vault, any>>,
|
||||
) {}
|
||||
private sortedMigrations = once(() => {
|
||||
const migrationsAsVersions = (
|
||||
this.migrations as Array<Migration<Store, any>>
|
||||
this.migrations as Array<Migration<Store, Vault, any>>
|
||||
).map((x) => [EmVer.parse(x.options.version), x] as const)
|
||||
migrationsAsVersions.sort((a, b) => a[0].compareForSort(b[0]))
|
||||
return migrationsAsVersions
|
||||
})
|
||||
private currentVersion = once(() => EmVer.parse(this.manifest.version))
|
||||
static of<Store, Migrations extends Array<Migration<Store, any>>>(
|
||||
manifest: SDKManifest,
|
||||
...migrations: EnsureUniqueId<Migrations>
|
||||
) {
|
||||
return new Migrations(manifest, migrations as Array<Migration<Store, any>>)
|
||||
static of<
|
||||
Store,
|
||||
Vault,
|
||||
Migrations extends Array<Migration<Store, Vault, any>>,
|
||||
>(manifest: SDKManifest, ...migrations: EnsureUniqueId<Migrations>) {
|
||||
return new Migrations(
|
||||
manifest,
|
||||
migrations as Array<Migration<Store, Vault, any>>,
|
||||
)
|
||||
}
|
||||
async init({
|
||||
effects,
|
||||
previousVersion,
|
||||
}: Parameters<ExpectedExports.init>[0]) {
|
||||
const utils = createUtils<Store>(effects)
|
||||
const utils = createUtils<Store, Vault>(effects)
|
||||
if (!!previousVersion) {
|
||||
const previousVersionEmVer = EmVer.parse(previousVersion)
|
||||
for (const [_, migration] of this.sortedMigrations()
|
||||
@@ -43,7 +46,7 @@ export class Migrations<Store> {
|
||||
effects,
|
||||
nextVersion,
|
||||
}: Parameters<ExpectedExports.uninit>[0]) {
|
||||
const utils = createUtils<Store>(effects)
|
||||
const utils = createUtils<Store, Vault>(effects)
|
||||
if (!!nextVersion) {
|
||||
const nextVersionEmVer = EmVer.parse(nextVersion)
|
||||
const reversed = [...this.sortedMigrations()].reverse()
|
||||
@@ -58,15 +61,16 @@ export class Migrations<Store> {
|
||||
|
||||
export function setupMigrations<
|
||||
Store,
|
||||
Migrations extends Array<Migration<Store, any>>,
|
||||
Vault,
|
||||
Migrations extends Array<Migration<Store, Vault, any>>,
|
||||
>(manifest: SDKManifest, ...migrations: EnsureUniqueId<Migrations>) {
|
||||
return Migrations.of<Store, Migrations>(manifest, ...migrations)
|
||||
return Migrations.of<Store, Vault, Migrations>(manifest, ...migrations)
|
||||
}
|
||||
|
||||
// prettier-ignore
|
||||
export type EnsureUniqueId<A, B = A, ids = never> =
|
||||
B extends [] ? A :
|
||||
B extends [Migration<any, infer id>, ...infer Rest] ? (
|
||||
B extends [Migration<any,any, infer id>, ...infer Rest] ? (
|
||||
id extends ids ? "One of the ids are not unique"[] :
|
||||
EnsureUniqueId<A, Rest, id | ids>
|
||||
) : "There exists a migration that is not a Migration"[]
|
||||
|
||||
@@ -3,10 +3,10 @@ import { Migrations } from "./migrations/setupMigrations"
|
||||
import { Install } from "./setupInstall"
|
||||
import { Uninstall } from "./setupUninstall"
|
||||
|
||||
export function setupInit<Store>(
|
||||
migrations: Migrations<Store>,
|
||||
install: Install<Store>,
|
||||
uninstall: Uninstall<Store>,
|
||||
export function setupInit<Store, Vault>(
|
||||
migrations: Migrations<Store, Vault>,
|
||||
install: Install<Store, Vault>,
|
||||
uninstall: Uninstall<Store, Vault>,
|
||||
): {
|
||||
init: ExpectedExports.init
|
||||
uninit: ExpectedExports.uninit
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Effects, ExpectedExports } from "../types"
|
||||
import { Utils, utils } from "../util/utils"
|
||||
|
||||
export type InstallFn<Store> = (opts: {
|
||||
export type InstallFn<Store, Vault> = (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
export class Install<Store> {
|
||||
private constructor(readonly fn: InstallFn<Store>) {}
|
||||
static of<Store>(fn: InstallFn<Store>) {
|
||||
export class Install<Store, Vault> {
|
||||
private constructor(readonly fn: InstallFn<Store, Vault>) {}
|
||||
static of<Store, Vault>(fn: InstallFn<Store, Vault>) {
|
||||
return new Install(fn)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@ export class Install<Store> {
|
||||
}
|
||||
}
|
||||
|
||||
export function setupInstall<Store>(fn: InstallFn<Store>) {
|
||||
export function setupInstall<Store, Vault>(fn: InstallFn<Store, Vault>) {
|
||||
return Install.of(fn)
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Effects, ExpectedExports } from "../types"
|
||||
import { Utils, utils } from "../util/utils"
|
||||
|
||||
export type UninstallFn<Store> = (opts: {
|
||||
export type UninstallFn<Store, Vault> = (opts: {
|
||||
effects: Effects
|
||||
utils: Utils<Store>
|
||||
utils: Utils<Store, Vault>
|
||||
}) => Promise<void>
|
||||
export class Uninstall<Store> {
|
||||
private constructor(readonly fn: UninstallFn<Store>) {}
|
||||
static of<Store>(fn: UninstallFn<Store>) {
|
||||
export class Uninstall<Store, Vault> {
|
||||
private constructor(readonly fn: UninstallFn<Store, Vault>) {}
|
||||
static of<Store, Vault>(fn: UninstallFn<Store, Vault>) {
|
||||
return new Uninstall(fn)
|
||||
}
|
||||
|
||||
@@ -23,6 +23,6 @@ export class Uninstall<Store> {
|
||||
}
|
||||
}
|
||||
|
||||
export function setupUninstall<Store>(fn: UninstallFn<Store>) {
|
||||
export function setupUninstall<Store, Vault>(fn: UninstallFn<Store, Vault>) {
|
||||
return Uninstall.of(fn)
|
||||
}
|
||||
|
||||
@@ -23,17 +23,17 @@ import "./Daemons"
|
||||
* @param fn
|
||||
* @returns
|
||||
*/
|
||||
export const setupMain = <Store>(
|
||||
export const setupMain = <Store, Vault>(
|
||||
fn: (o: {
|
||||
effects: Effects
|
||||
started(onTerm: () => void): null
|
||||
utils: Utils<Store, {}>
|
||||
utils: Utils<Store, Vault, {}>
|
||||
}) => Promise<Daemons<any>>,
|
||||
): ExpectedExports.main => {
|
||||
return async (options) => {
|
||||
const result = await fn({
|
||||
...options,
|
||||
utils: createMainUtils<Store>(options.effects),
|
||||
utils: createMainUtils<Store, Vault>(options.effects),
|
||||
})
|
||||
await result.build().then((x) => x.wait())
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { Parser } from "ts-matches"
|
||||
import { Effects, EnsureStorePath } from "../types"
|
||||
import { NoAny } from "../util"
|
||||
|
||||
export class GetStore<Store, Path extends string> {
|
||||
constructor(
|
||||
|
||||
@@ -4,4 +4,5 @@ export type Manifest = any
|
||||
export const sdk = StartSdk.of()
|
||||
.withManifest({} as any)
|
||||
.withStore<{ storeRoot: { storeLeaf: "value" } }>()
|
||||
.withVault<{ vaultRoot: "value" }>()
|
||||
.build(true)
|
||||
|
||||
@@ -2,11 +2,14 @@ import { Effects } from "../types"
|
||||
import { createMainUtils } from "../util"
|
||||
import { utils } from "../util/utils"
|
||||
|
||||
type WrapperType = {
|
||||
type Store = {
|
||||
config: {
|
||||
someValue: "a" | "b"
|
||||
}
|
||||
}
|
||||
type Vault = {
|
||||
hello: string
|
||||
}
|
||||
const todo = <A>(): A => {
|
||||
throw new Error("not implemented")
|
||||
}
|
||||
@@ -14,14 +17,14 @@ const noop = () => {}
|
||||
describe("Store", () => {
|
||||
test("types", async () => {
|
||||
;async () => {
|
||||
utils<WrapperType>(todo<Effects>()).store.setOwn("/config", {
|
||||
utils<Store>(todo<Effects>()).store.setOwn("/config", {
|
||||
someValue: "a",
|
||||
})
|
||||
utils<WrapperType>(todo<Effects>()).store.setOwn("/config/someValue", "b")
|
||||
utils<WrapperType>(todo<Effects>()).store.setOwn("", {
|
||||
utils<Store>(todo<Effects>()).store.setOwn("/config/someValue", "b")
|
||||
utils<Store>(todo<Effects>()).store.setOwn("", {
|
||||
config: { someValue: "b" },
|
||||
})
|
||||
utils<WrapperType>(todo<Effects>()).store.setOwn(
|
||||
utils<Store>(todo<Effects>()).store.setOwn(
|
||||
"/config/someValue",
|
||||
|
||||
// @ts-expect-error Type is wrong for the setting value
|
||||
@@ -33,75 +36,75 @@ describe("Store", () => {
|
||||
"someValue",
|
||||
)
|
||||
|
||||
todo<Effects>().store.set<WrapperType, "/config/someValue">({
|
||||
todo<Effects>().store.set<Store, "/config/someValue">({
|
||||
path: "/config/someValue",
|
||||
value: "b",
|
||||
})
|
||||
todo<Effects>().store.set<WrapperType, "/config/some2Value">({
|
||||
todo<Effects>().store.set<Store, "/config/some2Value">({
|
||||
//@ts-expect-error Path is wrong
|
||||
path: "/config/someValue",
|
||||
//@ts-expect-error Path is wrong
|
||||
value: "someValueIn",
|
||||
})
|
||||
todo<Effects>().store.set<WrapperType, "/config/someValue">({
|
||||
todo<Effects>().store.set<Store, "/config/someValue">({
|
||||
//@ts-expect-error Path is wrong
|
||||
path: "/config/some2Value",
|
||||
value: "a",
|
||||
})
|
||||
;(await createMainUtils<WrapperType>(todo<Effects>())
|
||||
;(await createMainUtils<Store, Vault>(todo<Effects>())
|
||||
.store.getOwn("/config/someValue")
|
||||
.const()) satisfies string
|
||||
;(await createMainUtils<WrapperType>(todo<Effects>())
|
||||
;(await createMainUtils<Store, Vault>(todo<Effects>())
|
||||
.store.getOwn("/config")
|
||||
.const()) satisfies WrapperType["config"]
|
||||
.const()) satisfies Store["config"]
|
||||
await createMainUtils(todo<Effects>())
|
||||
// @ts-expect-error Path is wrong
|
||||
.store.getOwn("/config/somdsfeValue")
|
||||
.const()
|
||||
/// ----------------- ERRORS -----------------
|
||||
|
||||
utils<WrapperType>(todo<Effects>()).store.setOwn("", {
|
||||
utils<Store>(todo<Effects>()).store.setOwn("", {
|
||||
// @ts-expect-error Type is wrong for the setting value
|
||||
config: { someValue: "notInAOrB" },
|
||||
})
|
||||
utils<WrapperType>(todo<Effects>()).store.setOwn(
|
||||
utils<Store>(todo<Effects>()).store.setOwn(
|
||||
"/config/someValue",
|
||||
// @ts-expect-error Type is wrong for the setting value
|
||||
"notInAOrB",
|
||||
)
|
||||
;(await utils<WrapperType>(todo<Effects>())
|
||||
;(await utils<Store>(todo<Effects>())
|
||||
.store.getOwn("/config/someValue")
|
||||
// @ts-expect-error Const should normally not be callable
|
||||
.const()) satisfies string
|
||||
;(await utils<WrapperType>(todo<Effects>())
|
||||
;(await utils<Store>(todo<Effects>())
|
||||
.store.getOwn("/config")
|
||||
// @ts-expect-error Const should normally not be callable
|
||||
.const()) satisfies WrapperType["config"]
|
||||
await utils<WrapperType>(todo<Effects>())
|
||||
.const()) satisfies Store["config"]
|
||||
await utils<Store>(todo<Effects>())
|
||||
// @ts-expect-error Path is wrong
|
||||
.store.getOwn("/config/somdsfeValue")
|
||||
// @ts-expect-error Const should normally not be callable
|
||||
.const()
|
||||
|
||||
///
|
||||
;(await utils<WrapperType>(todo<Effects>())
|
||||
;(await utils<Store>(todo<Effects>())
|
||||
.store.getOwn("/config/someValue")
|
||||
// @ts-expect-error satisfies type is wrong
|
||||
.const()) satisfies number
|
||||
;(await createMainUtils(todo<Effects>())
|
||||
// @ts-expect-error Path is wrong
|
||||
.store.getOwn("/config/")
|
||||
.const()) satisfies WrapperType["config"]
|
||||
;(await todo<Effects>().store.get<WrapperType, "/config/someValue">({
|
||||
.const()) satisfies Store["config"]
|
||||
;(await todo<Effects>().store.get<Store, "/config/someValue">({
|
||||
path: "/config/someValue",
|
||||
callback: noop,
|
||||
})) satisfies string
|
||||
await todo<Effects>().store.get<WrapperType, "/config/someValue">({
|
||||
await todo<Effects>().store.get<Store, "/config/someValue">({
|
||||
// @ts-expect-error Path is wrong as in it doesn't match above
|
||||
path: "/config/someV2alue",
|
||||
callback: noop,
|
||||
})
|
||||
await todo<Effects>().store.get<WrapperType, "/config/someV2alue">({
|
||||
await todo<Effects>().store.get<Store, "/config/someV2alue">({
|
||||
// @ts-expect-error Path is wrong as in it doesn't exists in wrapper type
|
||||
path: "/config/someV2alue",
|
||||
callback: noop,
|
||||
|
||||
@@ -398,7 +398,7 @@ export type Effects = {
|
||||
|
||||
vault: {
|
||||
list(): Promise<string[]>
|
||||
get(opt: { key: string }): 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>
|
||||
|
||||
@@ -22,8 +22,8 @@ export const isKnownError = (e: unknown): e is T.KnownError =>
|
||||
declare const affine: unique symbol
|
||||
|
||||
export const createUtils = utils
|
||||
export const createMainUtils = <Store>(effects: T.Effects) =>
|
||||
createUtils<Store, {}>(effects)
|
||||
export const createMainUtils = <Store, Vault>(effects: T.Effects) =>
|
||||
createUtils<Store, Vault, {}>(effects)
|
||||
|
||||
type NeverPossible = { [affine]: string }
|
||||
export type NoAny<A> = NeverPossible extends A
|
||||
|
||||
@@ -15,8 +15,9 @@ import { TorHostname } from "../mainFn/TorHostname"
|
||||
import { DefaultString } from "../config/configTypes"
|
||||
import { getDefaultString } from "./getDefaultString"
|
||||
import { GetStore, getStore } from "../store/getStore"
|
||||
import { GetVault, getVault } from "./getVault"
|
||||
|
||||
export type Utils<Store, WrapperOverWrite = { const: never }> = {
|
||||
export type Utils<Store, Vault, WrapperOverWrite = { const: never }> = {
|
||||
createOrUpdateVault: (opts: {
|
||||
key: string
|
||||
value: string | null | undefined
|
||||
@@ -41,6 +42,10 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
|
||||
value: ExtractStore<Store, Path>,
|
||||
) => Promise<void>
|
||||
}
|
||||
vault: {
|
||||
get: (key: keyof Vault & string) => GetVault<Vault> & WrapperOverWrite
|
||||
set: (key: keyof Vault & string, value: string) => Promise<void>
|
||||
}
|
||||
checkPortListening(
|
||||
port: number,
|
||||
options: {
|
||||
@@ -63,9 +68,13 @@ export type Utils<Store, WrapperOverWrite = { const: never }> = {
|
||||
torHostName: (id: string) => TorHostname
|
||||
nullIfEmpty: typeof nullIfEmpty
|
||||
}
|
||||
export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
export const utils = <
|
||||
Store = never,
|
||||
Vault = never,
|
||||
WrapperOverWrite = { const: never },
|
||||
>(
|
||||
effects: T.Effects,
|
||||
): Utils<Store, WrapperOverWrite> => ({
|
||||
): Utils<Store, Vault, WrapperOverWrite> => ({
|
||||
createOrUpdateVault: async ({
|
||||
key,
|
||||
value,
|
||||
@@ -79,7 +88,7 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
await effects.vault.set({ key, value })
|
||||
return value
|
||||
}
|
||||
if (await effects.vault.get({ key })) {
|
||||
if (await effects.vault.get({ key, callback: noop })) {
|
||||
return null
|
||||
}
|
||||
const newValue = getDefaultString(generator)
|
||||
@@ -93,7 +102,7 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
fileHelper.write(data, effects),
|
||||
nullIfEmpty,
|
||||
store: {
|
||||
get: <Store = never, Path extends string = never>(
|
||||
get: <Path extends string = never>(
|
||||
packageId: string,
|
||||
path: T.EnsureStorePath<Store, Path>,
|
||||
) =>
|
||||
@@ -112,4 +121,12 @@ export const utils = <Store = never, WrapperOverWrite = { const: never }>(
|
||||
bindLan: async (port: number) => LocalPort.bindLan(effects, port),
|
||||
networkBuilder: () => NetworkBuilder.of(effects),
|
||||
torHostName: (id: string) => TorHostname.of(effects, id),
|
||||
|
||||
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 }),
|
||||
},
|
||||
})
|
||||
function noop(): void {}
|
||||
|
||||
Reference in New Issue
Block a user