From aded4f6b3d88710393016ac0c749f5afb943b57f Mon Sep 17 00:00:00 2001 From: BluJ Date: Mon, 8 May 2023 11:49:56 -0600 Subject: [PATCH 01/26] chore: Wrapper Data Contract --- lib/actions/createAction.ts | 35 ++++---- lib/autoconfig/AutoConfig.ts | 6 +- lib/autoconfig/setupAutoConfig.ts | 8 +- lib/config/builder/list.ts | 3 + lib/config/builder/value.ts | 92 ++++++++------------- lib/config/constants.ts | 14 +++- lib/config/setupConfig.ts | 6 +- lib/inits/migrations/Migration.ts | 28 ++++--- lib/inits/migrations/setupMigrations.ts | 38 ++++++--- lib/inits/setupInit.ts | 2 +- lib/inits/setupInstall.ts | 32 +++++-- lib/inits/setupUninstall.ts | 28 +++++-- lib/mainFn/index.ts | 10 ++- lib/test/configBuilder.test.ts | 68 ++++++++------- lib/test/wrapperData.test.ts | 34 ++++---- lib/util/index.ts | 32 +++---- lib/{util => wrapperData}/getWrapperData.ts | 2 +- lib/wrapperData/wrapperDataContract.ts | 14 ++++ 18 files changed, 265 insertions(+), 187 deletions(-) rename lib/{util => wrapperData}/getWrapperData.ts (98%) create mode 100644 lib/wrapperData/wrapperDataContract.ts diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index 8889ffc..25591c3 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -1,51 +1,56 @@ import { Config, ExtractConfigType } from "../config/builder/config" import { ActionMetaData, ActionResult, Effects, ExportedAction } from "../types" -import { Utils, utils } from "../util" +import { Utils, createUtils, utils } from "../util" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" export class CreatedAction< - WrapperData, - ConfigType extends - | Record - | Config - | Config, + WD, + ConfigType extends Record | Config | Config, Type extends Record = ExtractConfigType, > { private constructor( + readonly wrapperDataContract: WrapperDataContract, public readonly myMetaData: ActionMetaData, readonly fn: (options: { effects: Effects - utils: Utils + utils: Utils input: Type }) => Promise, - readonly input: Config | Config, + readonly input: Config | Config, ) {} public validator = this.input.validator static of< - WrapperData, + WD, ConfigType extends | Record | Config | Config, Type extends Record = ExtractConfigType, >( + wrapperDataContract: WrapperDataContract, metaData: Omit & { - input: Config | Config + input: Config | Config }, fn: (options: { effects: Effects - utils: Utils + utils: Utils input: Type }) => Promise, ) { const { input, ...rest } = metaData - return new CreatedAction(rest, fn, input) + return new CreatedAction( + wrapperDataContract, + rest, + fn, + input, + ) } exportedAction: ExportedAction = ({ effects, input }) => { return this.fn({ effects, - utils: utils(effects), + utils: createUtils(this.wrapperDataContract, effects), input: this.validator.unsafeCast(input), }) } @@ -53,7 +58,7 @@ export class CreatedAction< run = async ({ effects, input }: { effects: Effects; input?: Type }) => { return this.fn({ effects, - utils: utils(effects), + utils: createUtils(this.wrapperDataContract, effects), input: this.validator.unsafeCast(input), }) } @@ -61,7 +66,7 @@ export class CreatedAction< async getConfig({ effects }: { effects: Effects }) { return this.input.build({ effects, - utils: utils(effects) as any, + utils: createUtils(this.wrapperDataContract, effects) as any, }) } } diff --git a/lib/autoconfig/AutoConfig.ts b/lib/autoconfig/AutoConfig.ts index 2b91d38..a558ce2 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/autoconfig/AutoConfig.ts @@ -2,6 +2,7 @@ import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util" import { deepEqual } from "../util/deepEqual" import { deepMerge } from "../util/deepMerge" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" export type AutoConfigFrom = { [key in keyof NestedConfigs & string]: (options: { @@ -13,6 +14,7 @@ export type AutoConfigFrom = { } export class AutoConfig { constructor( + readonly wrapperDataContract: WrapperDataContract, readonly configs: AutoConfigFrom, readonly path: keyof AutoConfigFrom, ) {} @@ -23,7 +25,7 @@ export class AutoConfig { const origConfig = JSON.parse(JSON.stringify(options.localConfig)) const newOptions = { ...options, - utils: utils(options.effects), + utils: utils(this.wrapperDataContract, options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, } @@ -44,7 +46,7 @@ export class AutoConfig { ): ReturnType { const newOptions = { ...options, - utils: utils(options.effects), + utils: utils(this.wrapperDataContract, options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, } diff --git a/lib/autoconfig/setupAutoConfig.ts b/lib/autoconfig/setupAutoConfig.ts index ca02420..42456f1 100644 --- a/lib/autoconfig/setupAutoConfig.ts +++ b/lib/autoconfig/setupAutoConfig.ts @@ -1,4 +1,5 @@ import { SDKManifest } from "../manifest/ManifestTypes" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" import { AutoConfig, AutoConfigFrom } from "./AutoConfig" export function setupAutoConfig< @@ -8,7 +9,10 @@ export function setupAutoConfig< NestedConfigs extends { [key in keyof Manifest["dependencies"]]: unknown }, ->(configs: AutoConfigFrom) { +>( + wrapperDataContract: WrapperDataContract, + configs: AutoConfigFrom, +) { type C = typeof configs const answer = { ...configs } as unknown as { [k in keyof C]: AutoConfig @@ -18,7 +22,7 @@ export function setupAutoConfig< WD, Input, NestedConfigs - >(configs, key as keyof typeof configs) + >(wrapperDataContract, configs, key as keyof typeof configs) } return answer } diff --git a/lib/config/builder/list.ts b/lib/config/builder/list.ts index 7157780..0867fc9 100644 --- a/lib/config/builder/list.ts +++ b/lib/config/builder/list.ts @@ -9,6 +9,7 @@ import { ValueSpecText, } from "../configTypes" import { Parser, arrayOf, number, string } from "ts-matches" +import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" /** * Used as a subtype of Value.list ```ts @@ -74,6 +75,7 @@ export class List { }, arrayOf(string)) } static dynamicText( + _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -167,6 +169,7 @@ export class List { }, arrayOf(number)) } static dynamicNumber( + _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index 0eb564f..ca81680 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -24,6 +24,7 @@ import { unknown, } from "ts-matches" import { once } from "../../util/once" +import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" type RequiredDefault = | false @@ -121,6 +122,7 @@ export class Value { ) } static dynamicToggle( + _wrapperDataContract: WrapperDataContract, a: LazyBuild< WD, { @@ -184,6 +186,7 @@ export class Value { ) } static dynamicText( + _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -255,6 +258,7 @@ export class Value { ) } static dynamicTextarea( + _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -321,6 +325,7 @@ export class Value { ) } static dynamicNumber( + _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -382,6 +387,7 @@ export class Value { } static dynamicColor( + _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -439,6 +445,7 @@ export class Value { ) } static dynamicDatetime( + _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -630,35 +637,34 @@ export class Value { asRequiredParser(aVariants.validator, a), ) } - static filteredUnion( - getDisabledFn: LazyBuild, + static filteredUnion< + Required extends RequiredDefault, + Type extends Record, + WD = never, + >( + _wrapperDataContract: WrapperDataContract, + getDisabledFn: LazyBuild, + a: { + name: string + description?: string | null + warning?: string | null + required: Required + }, + aVariants: Variants | Variants, ) { - return < - Required extends RequiredDefault, - Type extends Record, - >( - a: { - name: string - description?: string | null - warning?: string | null - required: Required - }, - aVariants: Variants | Variants, - ) => { - return new Value, WrapperData>( - async (options) => ({ - type: "union" as const, - description: null, - warning: null, - ...a, - variants: await aVariants.build(options as any), - ...requiredLikeToAbove(a.required), - disabled: (await getDisabledFn(options)) || [], - immutable: false, - }), - asRequiredParser(aVariants.validator, a), - ) - } + return new Value, WD>( + async (options) => ({ + type: "union" as const, + description: null, + warning: null, + ...a, + variants: await aVariants.build(options as any), + ...requiredLikeToAbove(a.required), + disabled: (await getDisabledFn(options)) || [], + immutable: false, + }), + asRequiredParser(aVariants.validator, a), + ) } static list(a: List) { @@ -686,33 +692,3 @@ export class Value { return this as any as Value } } - -type Wrapper = { test: 1 | "5" } -const valueA = Value.dynamicText(() => ({ - name: "a", - required: false, -})) -const variantForC = Variants.of({ - lnd: { - name: "lnd Name", - spec: Config.of({ - name: Value.text({ - name: "Node Name", - required: false, - }), - }), - }, -}) -const valueC = Value.filteredUnion(() => [])( - { name: "a", required: false }, - variantForC, -) -const valueB = Value.text({ - name: "a", - required: false, -}) -const test = Config.of({ - a: valueA, - b: valueB, - c: valueC, -}) diff --git a/lib/config/constants.ts b/lib/config/constants.ts index b2e4002..821c583 100644 --- a/lib/config/constants.ts +++ b/lib/config/constants.ts @@ -1,12 +1,18 @@ import { SmtpValue } from "../types" +import { + createWrapperDataContract, + neverWrapperDataContract, +} from "../wrapperData/wrapperDataContract" import { Config, ConfigSpecOf } from "./builder/config" import { Value } from "./builder/value" import { Variants } from "./builder/variants" -export const smtpConfig = Value.filteredUnion(async ({ effects, utils }) => { - const smtp = await utils.getSystemSmtp().once() - return smtp ? [] : ["system"] -})( +export const smtpConfig = Value.filteredUnion( + neverWrapperDataContract, + async ({ effects, utils }) => { + const smtp = await utils.getSystemSmtp().once() + return smtp ? [] : ["system"] + }, { name: "SMTP", description: "Optionally provide an SMTP server for sending email", diff --git a/lib/config/setupConfig.ts b/lib/config/setupConfig.ts index 07d0057..2e86a6b 100644 --- a/lib/config/setupConfig.ts +++ b/lib/config/setupConfig.ts @@ -4,6 +4,7 @@ import * as D from "./dependencies" import { Config, ExtractConfigType } from "./builder/config" import { Utils, utils } from "../util" import nullIfEmpty from "../util/nullIfEmpty" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" declare const dependencyProof: unique symbol export type DependenciesReceipt = void & { @@ -52,6 +53,7 @@ export function setupConfig< Manifest extends SDKManifest, Type extends Record = ExtractConfigType, >( + wrapperDataContract: WrapperDataContract, spec: Config | Config, write: Save, read: Read, @@ -66,7 +68,7 @@ export function setupConfig< const { restart } = await write({ input: JSON.parse(JSON.stringify(input)), effects, - utils: utils(effects), + utils: utils(wrapperDataContract, effects), dependencies: D.dependenciesSet(), }) if (restart) { @@ -74,7 +76,7 @@ export function setupConfig< } }) as ExpectedExports.setConfig, getConfig: (async ({ effects }) => { - const myUtils = utils(effects) + const myUtils = utils(wrapperDataContract, effects) const configValue = nullIfEmpty( (await read({ effects, utils: myUtils })) || null, ) diff --git a/lib/inits/migrations/Migration.ts b/lib/inits/migrations/Migration.ts index 3cb20dd..2047aea 100644 --- a/lib/inits/migrations/Migration.ts +++ b/lib/inits/migrations/Migration.ts @@ -1,27 +1,33 @@ import { ManifestVersion } from "../../manifest/ManifestTypes" import { Effects } from "../../types" +import { Utils } from "../../util" +import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" -export class Migration { +export class Migration { constructor( + readonly wrapperDataContract: WrapperDataContract, readonly options: { version: Version - up: (opts: { effects: Effects }) => Promise - down: (opts: { effects: Effects }) => Promise + up: (opts: { effects: Effects; utils: Utils }) => Promise + down: (opts: { effects: Effects; utils: Utils }) => Promise }, ) {} - static of(options: { - version: Version - up: (opts: { effects: Effects }) => Promise - down: (opts: { effects: Effects }) => Promise - }) { - return new Migration(options) + static of( + wrapperDataContract: WrapperDataContract, + options: { + version: Version + up: (opts: { effects: Effects; utils: Utils }) => Promise + down: (opts: { effects: Effects; utils: Utils }) => Promise + }, + ) { + return new Migration(wrapperDataContract, options) } - async up(opts: { effects: Effects }) { + async up(opts: { effects: Effects; utils: Utils }) { this.up(opts) } - async down(opts: { effects: Effects }) { + async down(opts: { effects: Effects; utils: Utils }) { this.down(opts) } } diff --git a/lib/inits/migrations/setupMigrations.ts b/lib/inits/migrations/setupMigrations.ts index 7034eca..fe35d1a 100644 --- a/lib/inits/migrations/setupMigrations.ts +++ b/lib/inits/migrations/setupMigrations.ts @@ -2,38 +2,47 @@ import { setupActions } from "../../actions/setupActions" import { EmVer } from "../../emverLite/mod" import { SDKManifest } from "../../manifest/ManifestTypes" import { ExpectedExports } from "../../types" +import { createUtils } from "../../util" import { once } from "../../util/once" +import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" import { Migration } from "./Migration" -export class Migrations { +export class Migrations { private constructor( + readonly wrapperDataContract: WrapperDataContract, readonly manifest: SDKManifest, - readonly migrations: Array>, + readonly migrations: Array>, ) {} private sortedMigrations = once(() => { - const migrationsAsVersions = (this.migrations as Array>).map( - (x) => [EmVer.parse(x.options.version), x] as const, - ) + const migrationsAsVersions = ( + this.migrations as Array> + ).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>>( + static of>>( + wrapperDataContract: WrapperDataContract, manifest: SDKManifest, ...migrations: EnsureUniqueId ) { - return new Migrations(manifest, migrations as Array>) + return new Migrations( + wrapperDataContract, + manifest, + migrations as Array>, + ) } async init({ effects, previousVersion, }: Parameters[0]) { + const utils = createUtils(this.wrapperDataContract, effects) if (!!previousVersion) { const previousVersionEmVer = EmVer.parse(previousVersion) for (const [_, migration] of this.sortedMigrations() .filter((x) => x[0].greaterThan(previousVersionEmVer)) .filter((x) => x[0].lessThanOrEqual(this.currentVersion()))) { - await migration.up({ effects }) + await migration.up({ effects, utils }) } } } @@ -41,29 +50,34 @@ export class Migrations { effects, nextVersion, }: Parameters[0]) { + const utils = createUtils(this.wrapperDataContract, effects) if (!!nextVersion) { const nextVersionEmVer = EmVer.parse(nextVersion) const reversed = [...this.sortedMigrations()].reverse() for (const [_, migration] of reversed .filter((x) => x[0].greaterThan(nextVersionEmVer)) .filter((x) => x[0].lessThanOrEqual(this.currentVersion()))) { - await migration.down({ effects }) + await migration.down({ effects, utils }) } } } } -export function setupMigrations>>( +export function setupMigrations< + WD, + Migrations extends Array>, +>( + wrapperDataContract: WrapperDataContract, manifest: SDKManifest, ...migrations: EnsureUniqueId ) { - return Migrations.of(manifest, ...migrations) + return Migrations.of(wrapperDataContract, manifest, ...migrations) } // prettier-ignore export type EnsureUniqueId = B extends [] ? A : - B extends [Migration, ...infer Rest] ? ( + B extends [Migration, ...infer Rest] ? ( id extends ids ? "One of the ids are not unique"[] : EnsureUniqueId ) : "There exists a migration that is not a Migration"[] diff --git a/lib/inits/setupInit.ts b/lib/inits/setupInit.ts index c782b2c..b8002ef 100644 --- a/lib/inits/setupInit.ts +++ b/lib/inits/setupInit.ts @@ -4,7 +4,7 @@ import { Install } from "./setupInstall" import { Uninstall } from "./setupUninstall" export function setupInit( - migrations: Migrations, + migrations: Migrations, install: Install, uninstall: Uninstall, ): { diff --git a/lib/inits/setupInstall.ts b/lib/inits/setupInstall.ts index 67c9569..330c35f 100644 --- a/lib/inits/setupInstall.ts +++ b/lib/inits/setupInstall.ts @@ -1,24 +1,38 @@ import { Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" -export type InstallFn = (opts: { +export type InstallFn = (opts: { effects: Effects - utils: Utils + utils: Utils }) => Promise -export class Install { - private constructor(readonly fn: InstallFn) {} - static of(fn: InstallFn) { - return new Install(fn) +export class Install { + private constructor( + readonly wrapperDataContract: WrapperDataContract, + readonly fn: InstallFn, + ) {} + static of( + wrapperDataContract: WrapperDataContract, + fn: InstallFn, + ) { + return new Install(wrapperDataContract, fn) } async init({ effects, previousVersion, }: Parameters[0]) { - if (!previousVersion) await this.fn({ effects, utils: utils(effects) }) + if (!previousVersion) + await this.fn({ + effects, + utils: utils(this.wrapperDataContract, effects), + }) } } -export function setupInstall(fn: InstallFn) { - return Install.of(fn) +export function setupInstall( + wrapperDataContract: WrapperDataContract, + fn: InstallFn, +) { + return Install.of(wrapperDataContract, fn) } diff --git a/lib/inits/setupUninstall.ts b/lib/inits/setupUninstall.ts index 5352001..ee83f89 100644 --- a/lib/inits/setupUninstall.ts +++ b/lib/inits/setupUninstall.ts @@ -1,24 +1,38 @@ import { Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" export type UninstallFn = (opts: { effects: Effects utils: Utils }) => Promise -export class Uninstall { - private constructor(readonly fn: UninstallFn) {} - static of(fn: UninstallFn) { - return new Uninstall(fn) +export class Uninstall { + private constructor( + readonly wrapperDataContract: WrapperDataContract, + readonly fn: UninstallFn, + ) {} + static of( + wrapperDataContract: WrapperDataContract, + fn: UninstallFn, + ) { + return new Uninstall(wrapperDataContract, fn) } async uninit({ effects, nextVersion, }: Parameters[0]) { - if (!nextVersion) await this.fn({ effects, utils: utils(effects) }) + if (!nextVersion) + await this.fn({ + effects, + utils: utils(this.wrapperDataContract, effects), + }) } } -export function setupUninstall(fn: UninstallFn) { - return Uninstall.of(fn) +export function setupUninstall( + wrapperDataContract: WrapperDataContract, + fn: UninstallFn, +) { + return Uninstall.of(wrapperDataContract, fn) } diff --git a/lib/mainFn/index.ts b/lib/mainFn/index.ts index 21b1fd3..9659518 100644 --- a/lib/mainFn/index.ts +++ b/lib/mainFn/index.ts @@ -1,5 +1,5 @@ import { Effects, ExpectedExports } from "../types" -import { Utils, utils } from "../util" +import { createMainUtils, Utils, utils } from "../util" import { Daemons } from "./Daemons" import "./exportInterfaces" import "./LocalBinding" @@ -11,6 +11,7 @@ import "./TorBinding" import "./TorHostname" import "./Daemons" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" /** * Used to ensure that the main function is running with the valid proofs. @@ -22,17 +23,18 @@ import "./Daemons" * @param fn * @returns */ -export const setupMain = ( +export const setupMain = ( + wrapperDataContract: WrapperDataContract, fn: (o: { effects: Effects started(onTerm: () => void): null - utils: Utils + utils: Utils }) => Promise>, ): ExpectedExports.main => { return async (options) => { const result = await fn({ ...options, - utils: utils(options.effects), + utils: createMainUtils(wrapperDataContract, options.effects), }) await result.build().then((x) => x.wait()) } diff --git a/lib/test/configBuilder.test.ts b/lib/test/configBuilder.test.ts index d196742..fa7717e 100644 --- a/lib/test/configBuilder.test.ts +++ b/lib/test/configBuilder.test.ts @@ -5,6 +5,10 @@ import { Value } from "../config/builder/value" import { Variants } from "../config/builder/variants" import { ValueSpec } from "../config/configTypes" import { Parser } from "ts-matches" +import { + createWrapperDataContract, + neverWrapperDataContract, +} from "../wrapperData/wrapperDataContract" type test = unknown | { test: 5 } describe("builder tests", () => { @@ -299,7 +303,7 @@ describe("values", () => { utils: "utils", } as any test("toggle", async () => { - const value = Value.dynamicToggle<{}>(async () => ({ + const value = Value.dynamicToggle(neverWrapperDataContract, async () => ({ name: "Testing", description: null, warning: null, @@ -317,7 +321,7 @@ describe("values", () => { }) }) test("text", async () => { - const value = Value.dynamicText(async () => ({ + const value = Value.dynamicText(neverWrapperDataContract, async () => ({ name: "Testing", required: { default: null }, })) @@ -333,7 +337,7 @@ describe("values", () => { }) }) test("text with default", async () => { - const value = Value.dynamicText(async () => ({ + const value = Value.dynamicText(neverWrapperDataContract, async () => ({ name: "Testing", required: { default: "this is a default value" }, })) @@ -348,7 +352,7 @@ describe("values", () => { }) }) test("optional text", async () => { - const value = Value.dynamicText(async () => ({ + const value = Value.dynamicText(neverWrapperDataContract, async () => ({ name: "Testing", required: false, })) @@ -364,7 +368,7 @@ describe("values", () => { }) }) test("color", async () => { - const value = Value.dynamicColor(async () => ({ + const value = Value.dynamicColor(neverWrapperDataContract, async () => ({ name: "Testing", required: false, description: null, @@ -383,17 +387,20 @@ describe("values", () => { }) }) test("datetime", async () => { - const value = Value.dynamicDatetime<{ test: "a" }>(async ({ utils }) => { - ;async () => { - ;(await utils.getOwnWrapperData("/test").once()) satisfies "a" - } + const value = Value.dynamicDatetime( + createWrapperDataContract<{ test: "a" }>(), + async ({ utils }) => { + ;async () => { + ;(await utils.getOwnWrapperData("/test").once()) satisfies "a" + } - return { - name: "Testing", - required: { default: null }, - inputmode: "date", - } - }) + return { + name: "Testing", + required: { default: null }, + inputmode: "date", + } + }, + ) const validator = value.validator validator.unsafeCast("2021-01-01") validator.unsafeCast(null) @@ -408,15 +415,18 @@ describe("values", () => { }) }) test("textarea", async () => { - const value = Value.dynamicTextarea(async () => ({ - name: "Testing", - required: false, - description: null, - warning: null, - minLength: null, - maxLength: null, - placeholder: null, - })) + const value = Value.dynamicTextarea( + neverWrapperDataContract, + async () => ({ + name: "Testing", + required: false, + description: null, + warning: null, + minLength: null, + maxLength: null, + placeholder: null, + }), + ) const validator = value.validator validator.unsafeCast("test text") expect(() => validator.unsafeCast(null)).toThrowError() @@ -427,7 +437,7 @@ describe("values", () => { }) }) test("number", async () => { - const value = Value.dynamicNumber(() => ({ + const value = Value.dynamicNumber(neverWrapperDataContract, () => ({ name: "Testing", required: { default: null }, integer: false, @@ -500,7 +510,9 @@ describe("values", () => { }) describe("filtering", () => { test("union", async () => { - const value = Value.filteredUnion(() => ["a", "c"])( + const value = Value.filteredUnion( + neverWrapperDataContract, + () => ["a", "c"], { name: "Testing", required: { default: null }, @@ -608,7 +620,7 @@ describe("Builder List", () => { describe("dynamic", () => { test("text", async () => { const value = Value.list( - List.dynamicText(() => ({ + List.dynamicText(neverWrapperDataContract, () => ({ name: "test", spec: { patterns: [] }, })), @@ -626,7 +638,7 @@ describe("Builder List", () => { }) test("number", async () => { const value = Value.list( - List.dynamicNumber(() => ({ + List.dynamicNumber(neverWrapperDataContract, () => ({ name: "test", spec: { integer: true }, })), diff --git a/lib/test/wrapperData.test.ts b/lib/test/wrapperData.test.ts index 76e6360..8e5078a 100644 --- a/lib/test/wrapperData.test.ts +++ b/lib/test/wrapperData.test.ts @@ -1,11 +1,13 @@ import { Effects } from "../types" -import { utils } from "../util" +import { createMainUtils, utils } from "../util" +import { createWrapperDataContract } from "../wrapperData/wrapperDataContract" type WrapperType = { config: { someValue: "a" | "b" } } +const wrapperDataContract = createWrapperDataContract() const todo = (): A => { throw new Error("not implemented") } @@ -13,23 +15,23 @@ const noop = () => {} describe("wrapperData", () => { test("types", async () => { ;async () => { - utils(todo()).setOwnWrapperData("/config", { + utils(wrapperDataContract, todo()).setOwnWrapperData("/config", { someValue: "a", }) - utils(todo()).setOwnWrapperData( + utils(wrapperDataContract, todo()).setOwnWrapperData( "/config/someValue", "b", ) - utils(todo()).setOwnWrapperData("", { + utils(wrapperDataContract, todo()).setOwnWrapperData("", { config: { someValue: "b" }, }) - utils(todo()).setOwnWrapperData( + utils(wrapperDataContract, todo()).setOwnWrapperData( "/config/someValue", // @ts-expect-error Type is wrong for the setting value 5, ) - utils(todo()).setOwnWrapperData( + utils(wrapperDataContract, todo()).setOwnWrapperData( // @ts-expect-error Path is wrong "/config/someVae3lue", "someValue", @@ -50,47 +52,47 @@ describe("wrapperData", () => { path: "/config/some2Value", value: "a", }) - ;(await utils(todo()) + ;(await createMainUtils(wrapperDataContract, todo()) .getOwnWrapperData("/config/someValue") .const()) satisfies string - ;(await utils(todo()) + ;(await createMainUtils(wrapperDataContract, todo()) .getOwnWrapperData("/config") .const()) satisfies WrapperType["config"] - await utils(todo()) + await createMainUtils(wrapperDataContract, todo()) // @ts-expect-error Path is wrong .getOwnWrapperData("/config/somdsfeValue") .const() /// ----------------- ERRORS ----------------- - utils(todo()).setOwnWrapperData("", { + utils(wrapperDataContract, todo()).setOwnWrapperData("", { // @ts-expect-error Type is wrong for the setting value config: { someValue: "notInAOrB" }, }) - utils(todo()).setOwnWrapperData( + utils(wrapperDataContract, todo()).setOwnWrapperData( "/config/someValue", // @ts-expect-error Type is wrong for the setting value "notInAOrB", ) - ;(await utils(todo()) + ;(await utils(wrapperDataContract, todo()) .getOwnWrapperData("/config/someValue") // @ts-expect-error Const should normally not be callable .const()) satisfies string - ;(await utils(todo()) + ;(await utils(wrapperDataContract, todo()) .getOwnWrapperData("/config") // @ts-expect-error Const should normally not be callable .const()) satisfies WrapperType["config"] - await utils(todo()) + await utils(wrapperDataContract, todo()) // @ts-expect-error Path is wrong .getOwnWrapperData("/config/somdsfeValue") // @ts-expect-error Const should normally not be callable .const() /// - ;(await utils(todo()) + ;(await utils(wrapperDataContract, todo()) .getOwnWrapperData("/config/someValue") // @ts-expect-error satisfies type is wrong .const()) satisfies number - ;(await utils(todo()) + ;(await createMainUtils(wrapperDataContract, todo()) // @ts-expect-error Path is wrong .getOwnWrapperData("/config/") .const()) satisfies WrapperType["config"] diff --git a/lib/util/index.ts b/lib/util/index.ts index 19eceb5..d3e9c12 100644 --- a/lib/util/index.ts +++ b/lib/util/index.ts @@ -2,7 +2,7 @@ import { Parser, string } from "ts-matches" import * as T from "../types" import FileHelper from "./fileHelper" import nullIfEmpty from "./nullIfEmpty" -import { GetWrapperData, getWrapperData } from "./getWrapperData" +import { GetWrapperData, getWrapperData } from "../wrapperData/getWrapperData" import { CheckResult, checkPortListening, @@ -13,7 +13,7 @@ import { GetSystemSmtp } from "./GetSystemSmtp" import "./nullIfEmpty" import "./fileHelper" -import "./getWrapperData" +import "../wrapperData/getWrapperData" import "./deepEqual" import "./deepMerge" import "./once" @@ -23,6 +23,7 @@ import { NetworkBuilder } from "../mainFn/NetworkBuilder" import { TorHostname } from "../mainFn/TorHostname" import { DefaultString } from "../config/configTypes" import { getDefaultString } from "./getDefaultString" +import { WrapperDataContract } from "../wrapperData/wrapperDataContract" // prettier-ignore export type FlattenIntersection = @@ -37,12 +38,6 @@ export const isKnownError = (e: unknown): e is T.KnownError => declare const affine: unique symbol -export type WrapperDataOptionals = { - validator?: Parser> - /** Defaults to what ever the package currently in */ - packageId?: string | undefined -} - export type Utils = { createOrUpdateVault: (opts: { key: string @@ -88,9 +83,10 @@ export type Utils = { torHostName: (id: string) => TorHostname nullIfEmpty: typeof nullIfEmpty } -export const utils = ( +export const utils = ( + _wrapperDataContract: WrapperDataContract, effects: T.Effects, -): Utils => ({ +): Utils => ({ createOrUpdateVault: async ({ key, value, @@ -125,12 +121,12 @@ export const utils = ( packageId, }) as any, getOwnWrapperData: ( - path: T.EnsureWrapperDataPath, - ) => getWrapperData(effects, path as any) as any, + path: T.EnsureWrapperDataPath, + ) => getWrapperData(effects, path as any) as any, setOwnWrapperData: ( - path: T.EnsureWrapperDataPath, - value: ExtractWrapperData, - ) => effects.setWrapperData({ value, path: path as any }), + path: T.EnsureWrapperDataPath, + value: ExtractWrapperData, + ) => effects.setWrapperData({ value, path: path as any }), checkPortListening: checkPortListening.bind(null, effects), checkWebUrl: checkWebUrl.bind(null, effects), bindLan: async (port: number) => LocalPort.bindLan(effects, port), @@ -138,6 +134,12 @@ export const utils = ( torHostName: (id: string) => TorHostname.of(effects, id), }) +export const createUtils = utils +export const createMainUtils = ( + wrapperDataContract: WrapperDataContract, + effects: T.Effects, +) => createUtils(wrapperDataContract, effects) + type NeverPossible = { [affine]: string } export type NoAny = NeverPossible extends A ? keyof NeverPossible extends keyof A diff --git a/lib/util/getWrapperData.ts b/lib/wrapperData/getWrapperData.ts similarity index 98% rename from lib/util/getWrapperData.ts rename to lib/wrapperData/getWrapperData.ts index f4c8fb9..8c2fe29 100644 --- a/lib/util/getWrapperData.ts +++ b/lib/wrapperData/getWrapperData.ts @@ -1,6 +1,6 @@ import { Parser } from "ts-matches" import { Effects, EnsureWrapperDataPath, ExtractWrapperData } from "../types" -import { NoAny } from "." +import { NoAny } from "../util" export class GetWrapperData { constructor( diff --git a/lib/wrapperData/wrapperDataContract.ts b/lib/wrapperData/wrapperDataContract.ts new file mode 100644 index 0000000..14bb975 --- /dev/null +++ b/lib/wrapperData/wrapperDataContract.ts @@ -0,0 +1,14 @@ +export declare const wrapperDataContractType: unique symbol +export type WrapperDataContract = { + [wrapperDataContractType]: A +} +export const neverWrapperDataContract: WrapperDataContract = null as any +/** + * Used to indicate the type of the wrapper data. To be used in areas where + * we need to know the wrapper data value + */ +export function createWrapperDataContract(): A extends never + ? "Wrapper Data Contract must be created with a generic" + : WrapperDataContract { + return null as any +} From e17668da007828e039d4aae9ae2b161d5cc578bb Mon Sep 17 00:00:00 2001 From: BluJ Date: Mon, 8 May 2023 12:39:30 -0600 Subject: [PATCH 02/26] chore: Update the types for the config and manifest --- lib/config/setupConfig.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/config/setupConfig.ts b/lib/config/setupConfig.ts index 2e86a6b..f010402 100644 --- a/lib/config/setupConfig.ts +++ b/lib/config/setupConfig.ts @@ -54,6 +54,7 @@ export function setupConfig< Type extends Record = ExtractConfigType, >( wrapperDataContract: WrapperDataContract, + _manifest: Manifest, spec: Config | Config, write: Save, read: Read, From 2b267c6c60603e59db8e3f45e9cecbadd916b9e1 Mon Sep 17 00:00:00 2001 From: BluJ Date: Mon, 8 May 2023 16:43:47 -0600 Subject: [PATCH 03/26] wip: Creating an sdk builder that has all the generics we need in one place --- lib/StartSDK.ts | 248 ++++++++++++++++++ lib/actions/createAction.ts | 33 +-- lib/config/builder/value.ts | 12 +- .../{constants.ts => configConstants.ts} | 0 ...{dependencies.ts => configDependencies.ts} | 6 +- lib/config/index.ts | 4 +- lib/config/setupConfig.ts | 6 +- lib/index.ts | 2 + .../{output.wrapperData.ts => output.sdk.ts} | 0 lib/{health => }/trigger/TriggerInput.ts | 0 .../trigger/changeOnFirstSuccess.ts | 0 lib/{health => }/trigger/cooldownTrigger.ts | 0 lib/{health => }/trigger/defaultTrigger.ts | 0 lib/{health => }/trigger/index.ts | 0 lib/util/index.ts | 1 - lib/wrapperData/wrapperDataContract.ts | 14 - 16 files changed, 275 insertions(+), 51 deletions(-) create mode 100644 lib/StartSDK.ts rename lib/config/{constants.ts => configConstants.ts} (100%) rename lib/config/{dependencies.ts => configDependencies.ts} (73%) rename lib/test/{output.wrapperData.ts => output.sdk.ts} (100%) rename lib/{health => }/trigger/TriggerInput.ts (100%) rename lib/{health => }/trigger/changeOnFirstSuccess.ts (100%) rename lib/{health => }/trigger/cooldownTrigger.ts (100%) rename lib/{health => }/trigger/defaultTrigger.ts (100%) rename lib/{health => }/trigger/index.ts (100%) delete mode 100644 lib/wrapperData/wrapperDataContract.ts diff --git a/lib/StartSDK.ts b/lib/StartSDK.ts new file mode 100644 index 0000000..56cfc32 --- /dev/null +++ b/lib/StartSDK.ts @@ -0,0 +1,248 @@ +import { AnyParser } from "ts-matches" +import { SDKManifest } from "./manifest/ManifestTypes" +import { RequiredDefault, Value } from "./config/builder/value" +import { Config, ExtractConfigType, LazyBuild } from "./config/builder/config" +import { + DefaultString, + Pattern, + RandomString, + ValueSpecDatetime, + ValueSpecText, +} from "./config/configTypes" +import { Variants } from "./config/builder/variants" +import { createAction } from "./actions/createAction" +import { ActionMetaData, Effects, ActionResult, Metadata } from "./types" +import { Utils } from "./util" + +// prettier-ignore +type AnyNeverCond = + T extends [] ? Else : + T extends [never, ...Array] ? Then : + T extends [any, ...infer U] ? AnyNeverCond : + never + +class StartSDK { + private constructor() {} + private anyOf( + a: A, + ): AnyNeverCond<[Manifest, Store], "Build not ready", A> { + return a as any + } + + static of() { + return new StartSDK() + } + withManifest() { + return new StartSDK() + } + withStore>() { + return new StartSDK() + } + + build() { + return this.anyOf({ + // TODO AutoConfig + // TODO Backup + // TODO Config + // TODO configConstants + // TODO configDependencies + createAction: < + Store, + ConfigType extends + | Record + | Config + | Config, + Type extends Record = ExtractConfigType, + >( + metaData: Omit & { + input: Config | Config + }, + fn: (options: { + effects: Effects + utils: Utils + input: Type + }) => Promise, + ) => createAction(metaData, fn), + // TODO Daemons + // TODO HealthCheck + // TODO healthCheckFns + // TODO List + // TODO mainNetwork + // TODO Migration + // TODO setupActions + // TODO setupAutoConfig + // TODO setupBackup + // TODO setupInit + // TODO setupInstall + // TODO setupMain + // TODO setupManifest + // TODO setupMigrations + // TODO setupUninstall + // TODO trigger changeOnFirstSuccess, cooldown, default + Value: { + toggle: Value.toggle, + text: Value.text, + textarea: Value.textarea, + number: Value.number, + color: Value.color, + datetime: Value.datetime, + select: Value.select, + multiselect: Value.multiselect, + object: Value.object, + union: Value.union, + list: Value.list, + dynamicToggle: ( + a: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + default: boolean + disabled?: false | string + } + >, + ) => Value.dynamicToggle(a), + dynamicText: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + required: RequiredDefault + + /** Default = false */ + masked?: boolean + placeholder?: string | null + minLength?: number | null + maxLength?: number | null + patterns?: Pattern[] + /** Default = 'text' */ + inputmode?: ValueSpecText["inputmode"] + generate?: null | RandomString + } + >, + ) => Value.dynamicText(getA), + dynamicTextarea: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + required: boolean + minLength?: number | null + maxLength?: number | null + placeholder?: string | null + disabled?: false | string + generate?: null | RandomString + } + >, + ) => Value.dynamicTextarea(getA), + dynamicNumber: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + required: RequiredDefault + min?: number | null + max?: number | null + /** Default = '1' */ + step?: string | null + integer: boolean + units?: string | null + placeholder?: string | null + disabled?: false | string + } + >, + ) => Value.dynamicNumber(getA), + dynamicColor: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + required: RequiredDefault + + disabled?: false | string + } + >, + ) => Value.dynamicColor(getA), + dynamicDatetime: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + required: RequiredDefault + /** Default = 'datetime-local' */ + inputmode?: ValueSpecDatetime["inputmode"] + min?: string | null + max?: string | null + step?: string | null + disabled?: false | string + } + >, + ) => Value.dynamicDatetime(getA), + dynamicSelect: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + required: RequiredDefault + values: Record + disabled?: false | string + } + >, + ) => Value.dynamicSelect(getA), + dynamicMultiselect: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + default: string[] + values: Record + minLength?: number | null + maxLength?: number | null + disabled?: false | string + } + >, + ) => Value.dynamicMultiselect(getA), + filteredUnion: < + Required extends RequiredDefault, + Type extends Record, + >( + getDisabledFn: LazyBuild, + a: { + name: string + description?: string | null + warning?: string | null + required: Required + }, + aVariants: Variants | Variants, + ) => + Value.filteredUnion( + getDisabledFn, + a, + aVariants, + ), + }, + // TODO Variants + }) + } +} +// TODO Test output.ts with sdk + +// const test = StartSDK.of() +// .withManifest() +// .withStore<{}>() +// .Value.dynamicToggle({} as any, {} as any) diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index 25591c3..0336807 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -1,56 +1,51 @@ import { Config, ExtractConfigType } from "../config/builder/config" import { ActionMetaData, ActionResult, Effects, ExportedAction } from "../types" import { Utils, createUtils, utils } from "../util" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" export class CreatedAction< - WD, - ConfigType extends Record | Config | Config, + Store, + ConfigType extends + | Record + | Config + | Config, Type extends Record = ExtractConfigType, > { private constructor( - readonly wrapperDataContract: WrapperDataContract, public readonly myMetaData: ActionMetaData, readonly fn: (options: { effects: Effects - utils: Utils + utils: Utils input: Type }) => Promise, - readonly input: Config | Config, + readonly input: Config | Config, ) {} public validator = this.input.validator static of< - WD, + Store, ConfigType extends | Record | Config | Config, Type extends Record = ExtractConfigType, >( - wrapperDataContract: WrapperDataContract, metaData: Omit & { - input: Config | Config + input: Config | Config }, fn: (options: { effects: Effects - utils: Utils + utils: Utils input: Type }) => Promise, ) { const { input, ...rest } = metaData - return new CreatedAction( - wrapperDataContract, - rest, - fn, - input, - ) + return new CreatedAction(rest, fn, input) } exportedAction: ExportedAction = ({ effects, input }) => { return this.fn({ effects, - utils: createUtils(this.wrapperDataContract, effects), + utils: createUtils(effects), input: this.validator.unsafeCast(input), }) } @@ -58,7 +53,7 @@ export class CreatedAction< run = async ({ effects, input }: { effects: Effects; input?: Type }) => { return this.fn({ effects, - utils: createUtils(this.wrapperDataContract, effects), + utils: createUtils(effects), input: this.validator.unsafeCast(input), }) } @@ -66,7 +61,7 @@ export class CreatedAction< async getConfig({ effects }: { effects: Effects }) { return this.input.build({ effects, - utils: createUtils(this.wrapperDataContract, effects) as any, + utils: createUtils(effects) as any, }) } } diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index ca81680..59e35fd 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -24,9 +24,8 @@ import { unknown, } from "ts-matches" import { once } from "../../util/once" -import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" -type RequiredDefault = +export type RequiredDefault = | false | { default: A | null @@ -96,7 +95,7 @@ const username = Value.string({ ``` */ export class Value { - private constructor( + protected constructor( public build: LazyBuild, public validator: Parser, ) {} @@ -122,7 +121,6 @@ export class Value { ) } static dynamicToggle( - _wrapperDataContract: WrapperDataContract, a: LazyBuild< WD, { @@ -186,7 +184,6 @@ export class Value { ) } static dynamicText( - _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -258,7 +255,6 @@ export class Value { ) } static dynamicTextarea( - _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -325,7 +321,6 @@ export class Value { ) } static dynamicNumber( - _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -387,7 +382,6 @@ export class Value { } static dynamicColor( - _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -445,7 +439,6 @@ export class Value { ) } static dynamicDatetime( - _wrapperDataContract: WrapperDataContract, getA: LazyBuild< WD, { @@ -642,7 +635,6 @@ export class Value { Type extends Record, WD = never, >( - _wrapperDataContract: WrapperDataContract, getDisabledFn: LazyBuild, a: { name: string diff --git a/lib/config/constants.ts b/lib/config/configConstants.ts similarity index 100% rename from lib/config/constants.ts rename to lib/config/configConstants.ts diff --git a/lib/config/dependencies.ts b/lib/config/configDependencies.ts similarity index 73% rename from lib/config/dependencies.ts rename to lib/config/configDependencies.ts index b974160..6b31abc 100644 --- a/lib/config/dependencies.ts +++ b/lib/config/configDependencies.ts @@ -1,12 +1,14 @@ import { SDKManifest } from "../manifest/ManifestTypes" import { Dependency } from "../types" -export type Dependencies = { +export type ConfigDependencies = { exists(id: keyof T["dependencies"]): Dependency running(id: keyof T["dependencies"]): Dependency } -export const dependenciesSet = (): Dependencies => ({ +export const configDependenciesSet = < + T extends SDKManifest, +>(): ConfigDependencies => ({ exists(id: keyof T["dependencies"]) { return { id, diff --git a/lib/config/index.ts b/lib/config/index.ts index ab95a64..510dc1c 100644 --- a/lib/config/index.ts +++ b/lib/config/index.ts @@ -1,5 +1,5 @@ import "./builder" import "./setupConfig" -import "./dependencies" -import "./constants" +import "./configDependencies" +import "./configConstants" diff --git a/lib/config/setupConfig.ts b/lib/config/setupConfig.ts index f010402..4432004 100644 --- a/lib/config/setupConfig.ts +++ b/lib/config/setupConfig.ts @@ -1,6 +1,6 @@ import { Effects, ExpectedExports } from "../types" import { SDKManifest } from "../manifest/ManifestTypes" -import * as D from "./dependencies" +import * as D from "./configDependencies" import { Config, ExtractConfigType } from "./builder/config" import { Utils, utils } from "../util" import nullIfEmpty from "../util/nullIfEmpty" @@ -22,7 +22,7 @@ export type Save< effects: Effects input: ExtractConfigType & Record utils: Utils - dependencies: D.Dependencies + dependencies: D.ConfigDependencies }) => Promise<{ dependenciesReceipt: DependenciesReceipt restart: boolean @@ -70,7 +70,7 @@ export function setupConfig< input: JSON.parse(JSON.stringify(input)), effects, utils: utils(wrapperDataContract, effects), - dependencies: D.dependenciesSet(), + dependencies: D.configDependenciesSet(), }) if (restart) { await effects.restart() diff --git a/lib/index.ts b/lib/index.ts index 85c32e1..4553d8e 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -19,3 +19,5 @@ import "./inits" export * as matches from "ts-matches" export * as YAML from "yaml" export * as TOML from "@iarna/toml" + +export class \ No newline at end of file diff --git a/lib/test/output.wrapperData.ts b/lib/test/output.sdk.ts similarity index 100% rename from lib/test/output.wrapperData.ts rename to lib/test/output.sdk.ts diff --git a/lib/health/trigger/TriggerInput.ts b/lib/trigger/TriggerInput.ts similarity index 100% rename from lib/health/trigger/TriggerInput.ts rename to lib/trigger/TriggerInput.ts diff --git a/lib/health/trigger/changeOnFirstSuccess.ts b/lib/trigger/changeOnFirstSuccess.ts similarity index 100% rename from lib/health/trigger/changeOnFirstSuccess.ts rename to lib/trigger/changeOnFirstSuccess.ts diff --git a/lib/health/trigger/cooldownTrigger.ts b/lib/trigger/cooldownTrigger.ts similarity index 100% rename from lib/health/trigger/cooldownTrigger.ts rename to lib/trigger/cooldownTrigger.ts diff --git a/lib/health/trigger/defaultTrigger.ts b/lib/trigger/defaultTrigger.ts similarity index 100% rename from lib/health/trigger/defaultTrigger.ts rename to lib/trigger/defaultTrigger.ts diff --git a/lib/health/trigger/index.ts b/lib/trigger/index.ts similarity index 100% rename from lib/health/trigger/index.ts rename to lib/trigger/index.ts diff --git a/lib/util/index.ts b/lib/util/index.ts index d3e9c12..8f68a67 100644 --- a/lib/util/index.ts +++ b/lib/util/index.ts @@ -84,7 +84,6 @@ export type Utils = { nullIfEmpty: typeof nullIfEmpty } export const utils = ( - _wrapperDataContract: WrapperDataContract, effects: T.Effects, ): Utils => ({ createOrUpdateVault: async ({ diff --git a/lib/wrapperData/wrapperDataContract.ts b/lib/wrapperData/wrapperDataContract.ts deleted file mode 100644 index 14bb975..0000000 --- a/lib/wrapperData/wrapperDataContract.ts +++ /dev/null @@ -1,14 +0,0 @@ -export declare const wrapperDataContractType: unique symbol -export type WrapperDataContract = { - [wrapperDataContractType]: A -} -export const neverWrapperDataContract: WrapperDataContract = null as any -/** - * Used to indicate the type of the wrapper data. To be used in areas where - * we need to know the wrapper data value - */ -export function createWrapperDataContract(): A extends never - ? "Wrapper Data Contract must be created with a generic" - : WrapperDataContract { - return null as any -} From 72df4cb502e00567c4dc0e7a6bef9baf431ccfee Mon Sep 17 00:00:00 2001 From: BluJ Date: Mon, 8 May 2023 16:59:56 -0600 Subject: [PATCH 04/26] wip: SDK up to createAction --- lib/StartSDK.ts | 37 +++++++++++++++++++++++++++++------ lib/autoconfig/AutoConfig.ts | 16 +++++++-------- lib/backup/Backups.ts | 9 +++++---- lib/config/configConstants.ts | 5 ----- 4 files changed, 43 insertions(+), 24 deletions(-) diff --git a/lib/StartSDK.ts b/lib/StartSDK.ts index 56cfc32..1f1f60b 100644 --- a/lib/StartSDK.ts +++ b/lib/StartSDK.ts @@ -11,8 +11,17 @@ import { } from "./config/configTypes" import { Variants } from "./config/builder/variants" import { createAction } from "./actions/createAction" -import { ActionMetaData, Effects, ActionResult, Metadata } from "./types" +import { + ActionMetaData, + Effects, + ActionResult, + Metadata, + BackupOptions, +} from "./types" import { Utils } from "./util" +import { AutoConfig, AutoConfigFrom } from "./autoconfig/AutoConfig" +import { BackupSet, Backups } from "./backup/Backups" +import { smtpConfig } from "./config/configConstants" // prettier-ignore type AnyNeverCond = @@ -41,11 +50,27 @@ class StartSDK { build() { return this.anyOf({ - // TODO AutoConfig - // TODO Backup - // TODO Config - // TODO configConstants - // TODO configDependencies + AutoConfig: ( + configs: AutoConfigFrom, + path: keyof AutoConfigFrom, + ) => new AutoConfig(configs, path), + Backups: { + volumes: (...volumeNames: Array) => + Backups.volumes(...volumeNames), + addSets: ( + ...options: BackupSet[] + ) => Backups.addSets(...options), + withOptions: (options?: Partial) => + Backups.with_options(options), + }, + Config: { + of: < + Spec extends Record | Value>, + >( + spec: Spec, + ) => Config.of(spec), + }, + configConstants: { smtpConfig }, createAction: < Store, ConfigType extends diff --git a/lib/autoconfig/AutoConfig.ts b/lib/autoconfig/AutoConfig.ts index a558ce2..5b6d2fb 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/autoconfig/AutoConfig.ts @@ -2,21 +2,19 @@ import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util" import { deepEqual } from "../util/deepEqual" import { deepMerge } from "../util/deepMerge" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" -export type AutoConfigFrom = { +export type AutoConfigFrom = { [key in keyof NestedConfigs & string]: (options: { effects: Effects localConfig: Input remoteConfig: NestedConfigs[key] - utils: Utils + utils: Utils }) => Promise> } -export class AutoConfig { +export class AutoConfig { constructor( - readonly wrapperDataContract: WrapperDataContract, - readonly configs: AutoConfigFrom, - readonly path: keyof AutoConfigFrom, + readonly configs: AutoConfigFrom, + readonly path: keyof AutoConfigFrom, ) {} async check( @@ -25,7 +23,7 @@ export class AutoConfig { const origConfig = JSON.parse(JSON.stringify(options.localConfig)) const newOptions = { ...options, - utils: utils(this.wrapperDataContract, options.effects), + utils: utils(options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, } @@ -46,7 +44,7 @@ export class AutoConfig { ): ReturnType { const newOptions = { ...options, - utils: utils(this.wrapperDataContract, options.effects), + utils: utils(options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, } diff --git a/lib/backup/Backups.ts b/lib/backup/Backups.ts index e088b80..0e1f4cb 100644 --- a/lib/backup/Backups.ts +++ b/lib/backup/Backups.ts @@ -1,6 +1,5 @@ import { SDKManifest } from "../manifest/ManifestTypes" import * as T from "../types" -import fs from "fs" export type BACKUP = "BACKUP" export const DEFAULT_OPTIONS: T.BackupOptions = { @@ -9,7 +8,7 @@ export const DEFAULT_OPTIONS: T.BackupOptions = { ignoreExisting: false, exclude: [], } -type BackupSet = { +export type BackupSet = { srcPath: string srcVolume: Volumes | BACKUP dstPath: string @@ -41,7 +40,7 @@ type BackupSet = { export class Backups { static BACKUP: BACKUP = "BACKUP" - constructor( + private constructor( private options = DEFAULT_OPTIONS, private backupSet = [] as BackupSet[], ) {} @@ -67,7 +66,9 @@ export class Backups { ) { return new Backups({ ...DEFAULT_OPTIONS, ...options }) } - set_options(options?: Partial) { + + static withOptions = Backups.with_options + setOptions(options?: Partial) { this.options = { ...this.options, ...options, diff --git a/lib/config/configConstants.ts b/lib/config/configConstants.ts index 821c583..4f0fc7a 100644 --- a/lib/config/configConstants.ts +++ b/lib/config/configConstants.ts @@ -1,14 +1,9 @@ import { SmtpValue } from "../types" -import { - createWrapperDataContract, - neverWrapperDataContract, -} from "../wrapperData/wrapperDataContract" import { Config, ConfigSpecOf } from "./builder/config" import { Value } from "./builder/value" import { Variants } from "./builder/variants" export const smtpConfig = Value.filteredUnion( - neverWrapperDataContract, async ({ effects, utils }) => { const smtp = await utils.getSystemSmtp().once() return smtp ? [] : ["system"] From 07493551b12038347b27567945420879b0cbb2c7 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 11:42:26 -0600 Subject: [PATCH 05/26] feat: creating the rest of the sdk --- lib/StartSDK.ts | 202 +++++++++++++++--- lib/actions/createAction.ts | 3 +- lib/autoconfig/AutoConfig.ts | 2 +- lib/autoconfig/setupAutoConfig.ts | 14 +- lib/config/builder/config.ts | 41 ++-- lib/config/builder/list.ts | 33 ++- lib/config/builder/value.ts | 87 ++++---- lib/config/builder/variants.ts | 40 ++-- lib/config/configConstants.ts | 2 +- lib/config/setupConfig.ts | 25 +-- lib/health/HealthCheck.ts | 6 +- lib/index.ts | 2 - lib/inits/migrations/Migration.ts | 29 ++- lib/inits/migrations/setupMigrations.ts | 33 +-- lib/inits/setupInit.ts | 8 +- lib/inits/setupInstall.ts | 30 +-- lib/inits/setupUninstall.ts | 30 +-- lib/mainFn/Daemons.ts | 6 +- lib/mainFn/index.ts | 11 +- .../getWrapperData.ts => store/getStore.ts} | 24 +-- lib/test/configBuilder.test.ts | 67 +++--- lib/test/makeOutput.ts | 3 +- lib/test/output.sdk.ts | 8 +- .../{wrapperData.test.ts => store.test.ts} | 66 +++--- lib/trigger/TriggerInput.ts | 2 +- lib/trigger/changeOnFirstSuccess.ts | 1 - lib/types.ts | 47 ++-- lib/util/index.ts | 122 +---------- lib/util/utils.ts | 115 ++++++++++ scripts/oldSpecToBuilder.ts | 13 +- 30 files changed, 568 insertions(+), 504 deletions(-) rename lib/{wrapperData/getWrapperData.ts => store/getStore.ts} (50%) rename lib/test/{wrapperData.test.ts => store.test.ts} (52%) create mode 100644 lib/util/utils.ts diff --git a/lib/StartSDK.ts b/lib/StartSDK.ts index 1f1f60b..e2427bf 100644 --- a/lib/StartSDK.ts +++ b/lib/StartSDK.ts @@ -1,11 +1,13 @@ import { AnyParser } from "ts-matches" -import { SDKManifest } from "./manifest/ManifestTypes" +import { ManifestVersion, SDKManifest } from "./manifest/ManifestTypes" import { RequiredDefault, Value } from "./config/builder/value" import { Config, ExtractConfigType, LazyBuild } from "./config/builder/config" import { DefaultString, + ListValueSpecText, Pattern, RandomString, + UniqueBy, ValueSpecDatetime, ValueSpecText, } from "./config/configTypes" @@ -18,10 +20,34 @@ import { Metadata, BackupOptions, } from "./types" -import { Utils } from "./util" +import { Utils } from "./util/utils" import { AutoConfig, AutoConfigFrom } from "./autoconfig/AutoConfig" import { BackupSet, Backups } from "./backup/Backups" import { smtpConfig } from "./config/configConstants" +import { Daemons } from "./mainFn/Daemons" +import { healthCheck } from "./health/HealthCheck" +import { + checkPortListening, + containsAddress, +} from "./health/checkFns/checkPortListening" +import { checkWebUrl, runHealthScript } from "./health/checkFns" +import { List } from "./config/builder/list" +import { Migration } from "./inits/migrations/Migration" +import { Install, InstallFn, setupInstall } from "./inits/setupInstall" +import { setupActions } from "./actions/setupActions" +import { setupAutoConfig } from "./autoconfig/setupAutoConfig" +import { SetupBackupsParams, setupBackups } from "./backup/setupBackups" +import { setupInit } from "./inits/setupInit" +import { + EnsureUniqueId, + Migrations, + setupMigrations, +} from "./inits/migrations/setupMigrations" +import { Uninstall, UninstallFn, setupUninstall } from "./inits/setupUninstall" +import { setupMain } from "./mainFn" +import { defaultTrigger } from "./trigger/defaultTrigger" +import { changeOnFirstSuccess, cooldownTrigger } from "./trigger" +import setupConfig, { Read, Save } from "./config/setupConfig" // prettier-ignore type AnyNeverCond = @@ -30,7 +56,7 @@ type AnyNeverCond = T extends [any, ...infer U] ? AnyNeverCond : never -class StartSDK { +export class StartSDK { private constructor() {} private anyOf( a: A, @@ -65,10 +91,10 @@ class StartSDK { }, Config: { of: < - Spec extends Record | Value>, + Spec extends Record | Value>, >( spec: Spec, - ) => Config.of(spec), + ) => Config.of(spec), }, configConstants: { smtpConfig }, createAction: < @@ -88,22 +114,137 @@ class StartSDK { input: Type }) => Promise, ) => createAction(metaData, fn), - // TODO Daemons - // TODO HealthCheck - // TODO healthCheckFns - // TODO List - // TODO mainNetwork - // TODO Migration - // TODO setupActions - // TODO setupAutoConfig - // TODO setupBackup - // TODO setupInit - // TODO setupInstall - // TODO setupMain - // TODO setupManifest - // TODO setupMigrations - // TODO setupUninstall - // TODO trigger changeOnFirstSuccess, cooldown, default + Daemons: { of: Daemons.of }, + healthCheck: { + checkPortListening, + checkWebUrl, + of: healthCheck, + runHealthScript, + }, + List: { + text: List.text, + number: List.number, + obj: >( + a: { + name: string + description?: string | null + warning?: string | null + /** Default [] */ + default?: [] + minLength?: number | null + maxLength?: number | null + }, + aSpec: { + spec: Config + displayAs?: null | string + uniqueBy?: null | UniqueBy + }, + ) => List.obj(a, aSpec), + dynamicText: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + /** Default = [] */ + default?: string[] + minLength?: number | null + maxLength?: number | null + disabled?: false | string + generate?: null | RandomString + spec: { + /** Default = false */ + masked?: boolean + placeholder?: string | null + minLength?: number | null + maxLength?: number | null + patterns: Pattern[] + /** Default = "text" */ + inputmode?: ListValueSpecText["inputmode"] + } + } + >, + ) => List.dynamicText(getA), + dynamicNumber: ( + getA: LazyBuild< + Store, + { + name: string + description?: string | null + warning?: string | null + /** Default = [] */ + default?: string[] + minLength?: number | null + maxLength?: number | null + disabled?: false | string + spec: { + integer: boolean + min?: number | null + max?: number | null + step?: string | null + units?: string | null + placeholder?: string | null + } + } + >, + ) => List.dynamicNumber(getA), + }, + Migration: { + of: (options: { + version: Version + up: (opts: { effects: Effects; utils: Utils }) => Promise + down: (opts: { + effects: Effects + utils: Utils + }) => Promise + }) => Migration.of(options), + }, + setupActions, + setupAutoConfig: < + Input, + NestedConfigs extends { + [key in keyof Manifest["dependencies"]]: unknown + }, + >( + configs: AutoConfigFrom, + ) => setupAutoConfig(configs), + setupBackups: (...args: SetupBackupsParams) => + setupBackups(...args), + setupConfig: < + ConfigType extends + | Record + | Config + | Config, + Type extends Record = ExtractConfigType, + >( + spec: Config | Config, + write: Save, + read: Read, + ) => setupConfig(spec, write, read), + setupInit: ( + migrations: Migrations, + install: Install, + uninstall: Uninstall, + ) => setupInit(migrations, install, uninstall), + setupInstall: (fn: InstallFn) => Install.of(fn), + setupMain: ( + fn: (o: { + effects: Effects + started(onTerm: () => void): null + utils: Utils + }) => Promise>, + ) => setupMain(fn), + setupMigrations: >>( + manifest: SDKManifest, + ...migrations: EnsureUniqueId + ) => setupMigrations(manifest, ...migrations), + setupUninstall: (fn: UninstallFn) => setupUninstall(fn), + trigger: { + defaultTrigger, + cooldownTrigger, + changeOnFirstSuccess, + }, Value: { toggle: Value.toggle, text: Value.text, @@ -261,13 +402,18 @@ class StartSDK { aVariants, ), }, - // TODO Variants + Variants: { + of: < + VariantValues extends { + [K in string]: { + name: string + spec: Config + } + }, + >( + a: VariantValues, + ) => Variants.of(a), + }, }) } } -// TODO Test output.ts with sdk - -// const test = StartSDK.of() -// .withManifest() -// .withStore<{}>() -// .Value.dynamicToggle({} as any, {} as any) diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index 0336807..a0cf09b 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -1,6 +1,7 @@ import { Config, ExtractConfigType } from "../config/builder/config" import { ActionMetaData, ActionResult, Effects, ExportedAction } from "../types" -import { Utils, createUtils, utils } from "../util" +import { createUtils } from "../util" +import { Utils, utils } from "../util/utils" export class CreatedAction< Store, diff --git a/lib/autoconfig/AutoConfig.ts b/lib/autoconfig/AutoConfig.ts index 5b6d2fb..590036a 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/autoconfig/AutoConfig.ts @@ -1,5 +1,5 @@ import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types" -import { Utils, utils } from "../util" +import { Utils, utils } from "../util/utils" import { deepEqual } from "../util/deepEqual" import { deepMerge } from "../util/deepMerge" diff --git a/lib/autoconfig/setupAutoConfig.ts b/lib/autoconfig/setupAutoConfig.ts index 42456f1..9258acd 100644 --- a/lib/autoconfig/setupAutoConfig.ts +++ b/lib/autoconfig/setupAutoConfig.ts @@ -1,28 +1,24 @@ import { SDKManifest } from "../manifest/ManifestTypes" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" import { AutoConfig, AutoConfigFrom } from "./AutoConfig" export function setupAutoConfig< - WD, + Store, Input, Manifest extends SDKManifest, NestedConfigs extends { [key in keyof Manifest["dependencies"]]: unknown }, ->( - wrapperDataContract: WrapperDataContract, - configs: AutoConfigFrom, -) { +>(configs: AutoConfigFrom) { type C = typeof configs const answer = { ...configs } as unknown as { - [k in keyof C]: AutoConfig + [k in keyof C]: AutoConfig } for (const key in configs) { answer[key as keyof typeof configs] = new AutoConfig< - WD, + Store, Input, NestedConfigs - >(wrapperDataContract, configs, key as keyof typeof configs) + >(configs, key as keyof typeof configs) } return answer } diff --git a/lib/config/builder/config.ts b/lib/config/builder/config.ts index 4fe6052..8f2e1ba 100644 --- a/lib/config/builder/config.ts +++ b/lib/config/builder/config.ts @@ -1,16 +1,16 @@ import { ValueSpec } from "../configTypes" -import { Utils } from "../../util" +import { Utils } from "../../util/utils" import { Value } from "./value" import { _ } from "../../util" import { Effects } from "../../types" import { Parser, object } from "ts-matches" -export type LazyBuildOptions = { +export type LazyBuildOptions = { effects: Effects - utils: Utils + utils: Utils } -export type LazyBuild = ( - options: LazyBuildOptions, +export type LazyBuild = ( + options: LazyBuildOptions, ) => Promise | ExpectedOut // prettier-ignore @@ -18,8 +18,8 @@ export type ExtractConfigType | Config | Config ? B : A -export type ConfigSpecOf, WD = never> = { - [K in keyof A]: Value +export type ConfigSpecOf, Store = never> = { + [K in keyof A]: Value } export type MaybeLazyValues = LazyBuild | A @@ -79,14 +79,14 @@ export const addNodesSpec = Config.of({ hostname: hostname, port: port }); ``` */ -export class Config, WD> { +export class Config, Store> { private constructor( private readonly spec: { - [K in keyof Type]: Value | Value + [K in keyof Type]: Value | Value }, public validator: Parser, ) {} - async build(options: LazyBuildOptions) { + async build(options: LazyBuildOptions) { const answer = {} as { [K in keyof Type]: ValueSpec } @@ -96,9 +96,10 @@ export class Config, WD> { return answer } - static of | Value>>( - spec: Spec, - ) { + static of< + Spec extends Record | Value>, + Store, + >(spec: Spec) { const validatorObj = {} as { [K in keyof Spec]: Parser } @@ -109,14 +110,12 @@ export class Config, WD> { return new Config< { [K in keyof Spec]: Spec[K] extends - | Value + | Value | Value ? T : never }, - { - [K in keyof Spec]: Spec[K] extends Value ? WD : never - }[keyof Spec] + Store >(spec, validator as any) } @@ -129,12 +128,12 @@ export class Config, WD> { required: false, }) - return Config.of()({ - myValue: a.withWrapperData(), + return Config.of()({ + myValue: a.withStore(), }) ``` */ - withWrapperData() { - return this as any as Config + withStore() { + return this as any as Config } } diff --git a/lib/config/builder/list.ts b/lib/config/builder/list.ts index 0867fc9..2b8c2b4 100644 --- a/lib/config/builder/list.ts +++ b/lib/config/builder/list.ts @@ -9,7 +9,6 @@ import { ValueSpecText, } from "../configTypes" import { Parser, arrayOf, number, string } from "ts-matches" -import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" /** * Used as a subtype of Value.list ```ts @@ -23,9 +22,9 @@ export const authorizationList = List.string({ export const auth = Value.list(authorizationList); ``` */ -export class List { +export class List { private constructor( - public build: LazyBuild, + public build: LazyBuild, public validator: Parser, ) {} static text( @@ -74,10 +73,9 @@ export class List { } satisfies ValueSpecListOf<"text"> }, arrayOf(string)) } - static dynamicText( - _wrapperDataContract: WrapperDataContract, + static dynamicText( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -101,7 +99,7 @@ export class List { } >, ) { - return new List(async (options) => { + return new List(async (options) => { const { spec: aSpec, ...a } = await getA(options) const spec = { type: "text" as const, @@ -168,10 +166,9 @@ export class List { } satisfies ValueSpecListOf<"number"> }, arrayOf(number)) } - static dynamicNumber( - _wrapperDataContract: WrapperDataContract, + static dynamicNumber( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -192,7 +189,7 @@ export class List { } >, ) { - return new List(async (options) => { + return new List(async (options) => { const { spec: aSpec, ...a } = await getA(options) const spec = { type: "number" as const, @@ -216,7 +213,7 @@ export class List { } }, arrayOf(number)) } - static obj, WrapperData>( + static obj, Store>( a: { name: string description?: string | null @@ -227,12 +224,12 @@ export class List { maxLength?: number | null }, aSpec: { - spec: Config + spec: Config displayAs?: null | string uniqueBy?: null | UniqueBy }, ) { - return new List(async (options) => { + return new List(async (options) => { const { spec: previousSpecSpec, ...restSpec } = aSpec const specSpec = await previousSpecSpec.build(options) const spec = { @@ -268,12 +265,12 @@ export class List { required: false, }) - return Config.of()({ - myValue: a.withWrapperData(), + return Config.of()({ + myValue: a.withStore(), }) ``` */ - withWrapperData() { - return this as any as List + withStore() { + return this as any as List } } diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index 59e35fd..7d1963e 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -94,9 +94,9 @@ const username = Value.string({ }); ``` */ -export class Value { +export class Value { protected constructor( - public build: LazyBuild, + public build: LazyBuild, public validator: Parser, ) {} static toggle(a: { @@ -120,9 +120,9 @@ export class Value { boolean, ) } - static dynamicToggle( + static dynamicToggle( a: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -132,7 +132,7 @@ export class Value { } >, ) { - return new Value( + return new Value( async (options) => ({ description: null, warning: null, @@ -183,9 +183,9 @@ export class Value { asRequiredParser(string, a), ) } - static dynamicText( + static dynamicText( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -204,7 +204,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "text" as const, @@ -254,9 +254,9 @@ export class Value { string, ) } - static dynamicTextarea( + static dynamicTextarea( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -270,7 +270,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { description: null, @@ -320,9 +320,9 @@ export class Value { asRequiredParser(number, a), ) } - static dynamicNumber( + static dynamicNumber( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -339,7 +339,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "number" as const, @@ -381,9 +381,9 @@ export class Value { ) } - static dynamicColor( + static dynamicColor( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -394,7 +394,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "color" as const, @@ -438,9 +438,9 @@ export class Value { asRequiredParser(string, a), ) } - static dynamicDatetime( + static dynamicDatetime( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -455,7 +455,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "datetime" as const, @@ -503,9 +503,9 @@ export class Value { ) as any, ) } - static dynamicSelect( + static dynamicSelect( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -516,7 +516,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { description: null, @@ -557,9 +557,9 @@ export class Value { ), ) } - static dynamicMultiselect( + static dynamicMultiselect( getA: LazyBuild< - WD, + Store, { name: string description?: string | null @@ -572,7 +572,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "multiselect" as const, @@ -586,15 +586,15 @@ export class Value { } }, arrayOf(string)) } - static object, WrapperData>( + static object, Store>( a: { name: string description?: string | null warning?: string | null }, - previousSpec: Config, + previousSpec: Config, ) { - return new Value(async (options) => { + return new Value(async (options) => { const spec = await previousSpec.build(options as any) return { type: "object" as const, @@ -605,7 +605,7 @@ export class Value { } }, previousSpec.validator) } - static union, Type, WrapperData>( + static union, Type, Store>( a: { name: string description?: string | null @@ -615,9 +615,9 @@ export class Value { Default is false */ immutable?: boolean }, - aVariants: Variants, + aVariants: Variants, ) { - return new Value, WrapperData>( + return new Value, Store>( async (options) => ({ type: "union" as const, description: null, @@ -633,18 +633,18 @@ export class Value { static filteredUnion< Required extends RequiredDefault, Type extends Record, - WD = never, + Store = never, >( - getDisabledFn: LazyBuild, + getDisabledFn: LazyBuild, a: { name: string description?: string | null warning?: string | null required: Required }, - aVariants: Variants | Variants, + aVariants: Variants | Variants, ) { - return new Value, WD>( + return new Value, Store>( async (options) => ({ type: "union" as const, description: null, @@ -659,11 +659,8 @@ export class Value { ) } - static list(a: List) { - return new Value( - (options) => a.build(options), - a.validator, - ) + static list(a: List) { + return new Value((options) => a.build(options), a.validator) } /** @@ -675,12 +672,12 @@ export class Value { required: false, }) - return Config.of()({ - myValue: a.withWrapperData(), + return Config.of()({ + myValue: a.withStore(), }) ``` */ - withWrapperData() { - return this as any as Value + withStore() { + return this as any as Value } } diff --git a/lib/config/builder/variants.ts b/lib/config/builder/variants.ts index b30b3f1..01f11be 100644 --- a/lib/config/builder/variants.ts +++ b/lib/config/builder/variants.ts @@ -51,24 +51,20 @@ export const pruning = Value.union( ); ``` */ -export class Variants { +export class Variants { + static text: any private constructor( - public build: LazyBuild, + public build: LazyBuild, public validator: Parser, ) {} - // A extends { - // [key: string]: { - // name: string - // spec: InputSpec - // } - // }, static of< VariantValues extends { [K in string]: { name: string - spec: Config | Config + spec: Config | Config } }, + Store, >(a: VariantValues) { const validator = anyOf( ...Object.entries(a).map(([name, { spec }]) => @@ -83,21 +79,13 @@ export class Variants { { [K in keyof VariantValues]: { unionSelectKey: K - unionValueKey: VariantValues[K]["spec"] extends - | Config - | Config - ? B - : never + // prettier-ignore + unionValueKey: + VariantValues[K]["spec"] extends (Config | Config) ? B : + never } }[keyof VariantValues], - { - [K in keyof VariantValues]: VariantValues[K] extends Config< - any, - infer C - > - ? C - : never - }[keyof VariantValues] + Store >(async (options) => { const variants = {} as { [K in keyof VariantValues]: { name: string; spec: InputSpec } @@ -121,12 +109,12 @@ export class Variants { required: false, }) - return Config.of()({ - myValue: a.withWrapperData(), + return Config.of()({ + myValue: a.withStore(), }) ``` */ - withWrapperData() { - return this as any as Variants + withStore() { + return this as any as Variants } } diff --git a/lib/config/configConstants.ts b/lib/config/configConstants.ts index 4f0fc7a..bddb668 100644 --- a/lib/config/configConstants.ts +++ b/lib/config/configConstants.ts @@ -18,7 +18,7 @@ export const smtpConfig = Value.filteredUnion( system: { name: "System Credentials", spec: Config.of({}) }, custom: { name: "Custom Credentials", - spec: Config.of>({ + spec: Config.of, never>({ server: Value.text({ name: "SMTP Server", required: { diff --git a/lib/config/setupConfig.ts b/lib/config/setupConfig.ts index 4432004..cfd1979 100644 --- a/lib/config/setupConfig.ts +++ b/lib/config/setupConfig.ts @@ -2,9 +2,8 @@ import { Effects, ExpectedExports } from "../types" import { SDKManifest } from "../manifest/ManifestTypes" import * as D from "./configDependencies" import { Config, ExtractConfigType } from "./builder/config" -import { Utils, utils } from "../util" +import { Utils, utils } from "../util/utils" import nullIfEmpty from "../util/nullIfEmpty" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" declare const dependencyProof: unique symbol export type DependenciesReceipt = void & { @@ -12,7 +11,7 @@ export type DependenciesReceipt = void & { } export type Save< - WD, + Store, A extends | Record | Config, any> @@ -21,21 +20,21 @@ export type Save< > = (options: { effects: Effects input: ExtractConfigType & Record - utils: Utils + utils: Utils dependencies: D.ConfigDependencies }) => Promise<{ dependenciesReceipt: DependenciesReceipt restart: boolean }> export type Read< - WD, + Store, A extends | Record | Config, any> | Config, never>, > = (options: { effects: Effects - utils: Utils + utils: Utils }) => Promise & Record)> /** * We want to setup a config export with a get and set, this @@ -45,7 +44,7 @@ export type Read< * @returns */ export function setupConfig< - WD, + Store, ConfigType extends | Record | Config @@ -53,11 +52,9 @@ export function setupConfig< Manifest extends SDKManifest, Type extends Record = ExtractConfigType, >( - wrapperDataContract: WrapperDataContract, - _manifest: Manifest, - spec: Config | Config, - write: Save, - read: Read, + spec: Config | Config, + write: Save, + read: Read, ) { const validator = spec.validator return { @@ -69,7 +66,7 @@ export function setupConfig< const { restart } = await write({ input: JSON.parse(JSON.stringify(input)), effects, - utils: utils(wrapperDataContract, effects), + utils: utils(effects), dependencies: D.configDependenciesSet(), }) if (restart) { @@ -77,7 +74,7 @@ export function setupConfig< } }) as ExpectedExports.setConfig, getConfig: (async ({ effects }) => { - const myUtils = utils(wrapperDataContract, effects) + const myUtils = utils(effects) const configValue = nullIfEmpty( (await read({ effects, utils: myUtils })) || null, ) diff --git a/lib/health/HealthCheck.ts b/lib/health/HealthCheck.ts index 7e2b54b..bb13313 100644 --- a/lib/health/HealthCheck.ts +++ b/lib/health/HealthCheck.ts @@ -2,9 +2,9 @@ import { InterfaceReceipt } from "../mainFn/interfaceReceipt" import { Daemon, Effects } from "../types" import { CheckResult } from "./checkFns/CheckResult" import { HealthReceipt } from "./HealthReceipt" -import { Trigger } from "./trigger" -import { TriggerInput } from "./trigger/TriggerInput" -import { defaultTrigger } from "./trigger/defaultTrigger" +import { Trigger } from "../trigger" +import { TriggerInput } from "../trigger/TriggerInput" +import { defaultTrigger } from "../trigger/defaultTrigger" import { once } from "../util/once" export function healthCheck(o: { diff --git a/lib/index.ts b/lib/index.ts index 4553d8e..85c32e1 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -19,5 +19,3 @@ import "./inits" export * as matches from "ts-matches" export * as YAML from "yaml" export * as TOML from "@iarna/toml" - -export class \ No newline at end of file diff --git a/lib/inits/migrations/Migration.ts b/lib/inits/migrations/Migration.ts index 2047aea..5723f8c 100644 --- a/lib/inits/migrations/Migration.ts +++ b/lib/inits/migrations/Migration.ts @@ -1,33 +1,28 @@ import { ManifestVersion } from "../../manifest/ManifestTypes" import { Effects } from "../../types" -import { Utils } from "../../util" -import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" +import { Utils } from "../../util/utils" -export class Migration { +export class Migration { constructor( - readonly wrapperDataContract: WrapperDataContract, readonly options: { version: Version - up: (opts: { effects: Effects; utils: Utils }) => Promise - down: (opts: { effects: Effects; utils: Utils }) => Promise + up: (opts: { effects: Effects; utils: Utils }) => Promise + down: (opts: { effects: Effects; utils: Utils }) => Promise }, ) {} - static of( - wrapperDataContract: WrapperDataContract, - options: { - version: Version - up: (opts: { effects: Effects; utils: Utils }) => Promise - down: (opts: { effects: Effects; utils: Utils }) => Promise - }, - ) { - return new Migration(wrapperDataContract, options) + static of(options: { + version: Version + up: (opts: { effects: Effects; utils: Utils }) => Promise + down: (opts: { effects: Effects; utils: Utils }) => Promise + }) { + return new Migration(options) } - async up(opts: { effects: Effects; utils: Utils }) { + async up(opts: { effects: Effects; utils: Utils }) { this.up(opts) } - async down(opts: { effects: Effects; utils: Utils }) { + async down(opts: { effects: Effects; utils: Utils }) { this.down(opts) } } diff --git a/lib/inits/migrations/setupMigrations.ts b/lib/inits/migrations/setupMigrations.ts index fe35d1a..7beb4de 100644 --- a/lib/inits/migrations/setupMigrations.ts +++ b/lib/inits/migrations/setupMigrations.ts @@ -4,39 +4,32 @@ import { SDKManifest } from "../../manifest/ManifestTypes" import { ExpectedExports } from "../../types" import { createUtils } from "../../util" import { once } from "../../util/once" -import { WrapperDataContract } from "../../wrapperData/wrapperDataContract" import { Migration } from "./Migration" -export class Migrations { +export class Migrations { private constructor( - readonly wrapperDataContract: WrapperDataContract, readonly manifest: SDKManifest, - readonly migrations: Array>, + readonly migrations: Array>, ) {} private sortedMigrations = once(() => { const migrationsAsVersions = ( - this.migrations as Array> + this.migrations as Array> ).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>>( - wrapperDataContract: WrapperDataContract, + static of>>( manifest: SDKManifest, ...migrations: EnsureUniqueId ) { - return new Migrations( - wrapperDataContract, - manifest, - migrations as Array>, - ) + return new Migrations(manifest, migrations as Array>) } async init({ effects, previousVersion, }: Parameters[0]) { - const utils = createUtils(this.wrapperDataContract, effects) + const utils = createUtils(effects) if (!!previousVersion) { const previousVersionEmVer = EmVer.parse(previousVersion) for (const [_, migration] of this.sortedMigrations() @@ -50,7 +43,7 @@ export class Migrations { effects, nextVersion, }: Parameters[0]) { - const utils = createUtils(this.wrapperDataContract, effects) + const utils = createUtils(effects) if (!!nextVersion) { const nextVersionEmVer = EmVer.parse(nextVersion) const reversed = [...this.sortedMigrations()].reverse() @@ -64,14 +57,10 @@ export class Migrations { } export function setupMigrations< - WD, - Migrations extends Array>, ->( - wrapperDataContract: WrapperDataContract, - manifest: SDKManifest, - ...migrations: EnsureUniqueId -) { - return Migrations.of(wrapperDataContract, manifest, ...migrations) + Store, + Migrations extends Array>, +>(manifest: SDKManifest, ...migrations: EnsureUniqueId) { + return Migrations.of(manifest, ...migrations) } // prettier-ignore diff --git a/lib/inits/setupInit.ts b/lib/inits/setupInit.ts index b8002ef..fac028f 100644 --- a/lib/inits/setupInit.ts +++ b/lib/inits/setupInit.ts @@ -3,10 +3,10 @@ import { Migrations } from "./migrations/setupMigrations" import { Install } from "./setupInstall" import { Uninstall } from "./setupUninstall" -export function setupInit( - migrations: Migrations, - install: Install, - uninstall: Uninstall, +export function setupInit( + migrations: Migrations, + install: Install, + uninstall: Uninstall, ): { init: ExpectedExports.init uninit: ExpectedExports.uninit diff --git a/lib/inits/setupInstall.ts b/lib/inits/setupInstall.ts index 330c35f..98e0be5 100644 --- a/lib/inits/setupInstall.ts +++ b/lib/inits/setupInstall.ts @@ -1,21 +1,14 @@ import { Effects, ExpectedExports } from "../types" -import { Utils, utils } from "../util" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" +import { Utils, utils } from "../util/utils" -export type InstallFn = (opts: { +export type InstallFn = (opts: { effects: Effects - utils: Utils + utils: Utils }) => Promise -export class Install { - private constructor( - readonly wrapperDataContract: WrapperDataContract, - readonly fn: InstallFn, - ) {} - static of( - wrapperDataContract: WrapperDataContract, - fn: InstallFn, - ) { - return new Install(wrapperDataContract, fn) +export class Install { + private constructor(readonly fn: InstallFn) {} + static of(fn: InstallFn) { + return new Install(fn) } async init({ @@ -25,14 +18,11 @@ export class Install { if (!previousVersion) await this.fn({ effects, - utils: utils(this.wrapperDataContract, effects), + utils: utils(effects), }) } } -export function setupInstall( - wrapperDataContract: WrapperDataContract, - fn: InstallFn, -) { - return Install.of(wrapperDataContract, fn) +export function setupInstall(fn: InstallFn) { + return Install.of(fn) } diff --git a/lib/inits/setupUninstall.ts b/lib/inits/setupUninstall.ts index ee83f89..6a76463 100644 --- a/lib/inits/setupUninstall.ts +++ b/lib/inits/setupUninstall.ts @@ -1,21 +1,14 @@ import { Effects, ExpectedExports } from "../types" -import { Utils, utils } from "../util" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" +import { Utils, utils } from "../util/utils" -export type UninstallFn = (opts: { +export type UninstallFn = (opts: { effects: Effects - utils: Utils + utils: Utils }) => Promise -export class Uninstall { - private constructor( - readonly wrapperDataContract: WrapperDataContract, - readonly fn: UninstallFn, - ) {} - static of( - wrapperDataContract: WrapperDataContract, - fn: UninstallFn, - ) { - return new Uninstall(wrapperDataContract, fn) +export class Uninstall { + private constructor(readonly fn: UninstallFn) {} + static of(fn: UninstallFn) { + return new Uninstall(fn) } async uninit({ @@ -25,14 +18,11 @@ export class Uninstall { if (!nextVersion) await this.fn({ effects, - utils: utils(this.wrapperDataContract, effects), + utils: utils(effects), }) } } -export function setupUninstall( - wrapperDataContract: WrapperDataContract, - fn: UninstallFn, -) { - return Uninstall.of(wrapperDataContract, fn) +export function setupUninstall(fn: UninstallFn) { + return Uninstall.of(fn) } diff --git a/lib/mainFn/Daemons.ts b/lib/mainFn/Daemons.ts index 247a83e..f489cfb 100644 --- a/lib/mainFn/Daemons.ts +++ b/lib/mainFn/Daemons.ts @@ -1,8 +1,8 @@ import { HealthReceipt } from "../health/HealthReceipt" import { CheckResult } from "../health/checkFns" -import { Trigger } from "../health/trigger" -import { TriggerInput } from "../health/trigger/TriggerInput" -import { defaultTrigger } from "../health/trigger/defaultTrigger" +import { Trigger } from "../trigger" +import { TriggerInput } from "../trigger/TriggerInput" +import { defaultTrigger } from "../trigger/defaultTrigger" import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types" import { InterfaceReceipt } from "./interfaceReceipt" type Daemon = { diff --git a/lib/mainFn/index.ts b/lib/mainFn/index.ts index 9659518..380dc7d 100644 --- a/lib/mainFn/index.ts +++ b/lib/mainFn/index.ts @@ -1,5 +1,6 @@ import { Effects, ExpectedExports } from "../types" -import { createMainUtils, Utils, utils } from "../util" +import { createMainUtils } from "../util" +import { Utils, utils } from "../util/utils" import { Daemons } from "./Daemons" import "./exportInterfaces" import "./LocalBinding" @@ -11,7 +12,6 @@ import "./TorBinding" import "./TorHostname" import "./Daemons" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" /** * Used to ensure that the main function is running with the valid proofs. @@ -23,18 +23,17 @@ import { WrapperDataContract } from "../wrapperData/wrapperDataContract" * @param fn * @returns */ -export const setupMain = ( - wrapperDataContract: WrapperDataContract, +export const setupMain = ( fn: (o: { effects: Effects started(onTerm: () => void): null - utils: Utils + utils: Utils }) => Promise>, ): ExpectedExports.main => { return async (options) => { const result = await fn({ ...options, - utils: createMainUtils(wrapperDataContract, options.effects), + utils: createMainUtils(options.effects), }) await result.build().then((x) => x.wait()) } diff --git a/lib/wrapperData/getWrapperData.ts b/lib/store/getStore.ts similarity index 50% rename from lib/wrapperData/getWrapperData.ts rename to lib/store/getStore.ts index 8c2fe29..bff6eec 100644 --- a/lib/wrapperData/getWrapperData.ts +++ b/lib/store/getStore.ts @@ -1,11 +1,11 @@ import { Parser } from "ts-matches" -import { Effects, EnsureWrapperDataPath, ExtractWrapperData } from "../types" +import { Effects, EnsureStorePath } from "../types" import { NoAny } from "../util" -export class GetWrapperData { +export class GetStore { constructor( readonly effects: Effects, - readonly path: Path & EnsureWrapperDataPath, + readonly path: Path & EnsureStorePath, readonly options: { /** Defaults to what ever the package currently in */ packageId?: string | undefined @@ -13,20 +13,20 @@ export class GetWrapperData { ) {} /** - * Returns the value of WrapperData at the provided path. Restart the service if the value changes + * Returns the value of Store at the provided path. Restart the service if the value changes */ const() { - return this.effects.getWrapperData({ + return this.effects.store.get({ ...this.options, path: this.path as any, callback: this.effects.restart, }) } /** - * Returns the value of WrapperData at the provided path. Does nothing if the value changes + * Returns the value of Store at the provided path. Does nothing if the value changes */ once() { - return this.effects.getWrapperData({ + return this.effects.store.get({ ...this.options, path: this.path as any, callback: () => {}, @@ -34,7 +34,7 @@ export class GetWrapperData { } /** - * Watches the value of WrapperData at the provided path. Takes a custom callback function to run whenever the value changes + * Watches the value of Store at the provided path. Takes a custom callback function to run whenever the value changes */ async *watch() { while (true) { @@ -42,7 +42,7 @@ export class GetWrapperData { const waitForNext = new Promise((resolve) => { callback = resolve }) - yield await this.effects.getWrapperData({ + yield await this.effects.store.get({ ...this.options, path: this.path as any, callback: () => callback(), @@ -51,13 +51,13 @@ export class GetWrapperData { } } } -export function getWrapperData( +export function getStore( effects: Effects, - path: Path & EnsureWrapperDataPath, + path: Path & EnsureStorePath, options: { /** Defaults to what ever the package currently in */ packageId?: string | undefined } = {}, ) { - return new GetWrapperData(effects, path as any, options) + return new GetStore(effects, path as any, options) } diff --git a/lib/test/configBuilder.test.ts b/lib/test/configBuilder.test.ts index fa7717e..1ea8835 100644 --- a/lib/test/configBuilder.test.ts +++ b/lib/test/configBuilder.test.ts @@ -4,13 +4,7 @@ import { List } from "../config/builder/list" import { Value } from "../config/builder/value" import { Variants } from "../config/builder/variants" import { ValueSpec } from "../config/configTypes" -import { Parser } from "ts-matches" -import { - createWrapperDataContract, - neverWrapperDataContract, -} from "../wrapperData/wrapperDataContract" -type test = unknown | { test: 5 } describe("builder tests", () => { test("text", async () => { const bitcoinPropertiesBuilt: { @@ -303,7 +297,7 @@ describe("values", () => { utils: "utils", } as any test("toggle", async () => { - const value = Value.dynamicToggle(neverWrapperDataContract, async () => ({ + const value = Value.dynamicToggle(async () => ({ name: "Testing", description: null, warning: null, @@ -321,7 +315,7 @@ describe("values", () => { }) }) test("text", async () => { - const value = Value.dynamicText(neverWrapperDataContract, async () => ({ + const value = Value.dynamicText(async () => ({ name: "Testing", required: { default: null }, })) @@ -337,7 +331,7 @@ describe("values", () => { }) }) test("text with default", async () => { - const value = Value.dynamicText(neverWrapperDataContract, async () => ({ + const value = Value.dynamicText(async () => ({ name: "Testing", required: { default: "this is a default value" }, })) @@ -352,7 +346,7 @@ describe("values", () => { }) }) test("optional text", async () => { - const value = Value.dynamicText(neverWrapperDataContract, async () => ({ + const value = Value.dynamicText(async () => ({ name: "Testing", required: false, })) @@ -368,7 +362,7 @@ describe("values", () => { }) }) test("color", async () => { - const value = Value.dynamicColor(neverWrapperDataContract, async () => ({ + const value = Value.dynamicColor(async () => ({ name: "Testing", required: false, description: null, @@ -387,20 +381,17 @@ describe("values", () => { }) }) test("datetime", async () => { - const value = Value.dynamicDatetime( - createWrapperDataContract<{ test: "a" }>(), - async ({ utils }) => { - ;async () => { - ;(await utils.getOwnWrapperData("/test").once()) satisfies "a" - } + const value = Value.dynamicDatetime<{ test: "a" }>(async ({ utils }) => { + ;async () => { + ;(await utils.store.getOwn("/test").once()) satisfies "a" + } - return { - name: "Testing", - required: { default: null }, - inputmode: "date", - } - }, - ) + return { + name: "Testing", + required: { default: null }, + inputmode: "date", + } + }) const validator = value.validator validator.unsafeCast("2021-01-01") validator.unsafeCast(null) @@ -415,18 +406,15 @@ describe("values", () => { }) }) test("textarea", async () => { - const value = Value.dynamicTextarea( - neverWrapperDataContract, - async () => ({ - name: "Testing", - required: false, - description: null, - warning: null, - minLength: null, - maxLength: null, - placeholder: null, - }), - ) + const value = Value.dynamicTextarea(async () => ({ + name: "Testing", + required: false, + description: null, + warning: null, + minLength: null, + maxLength: null, + placeholder: null, + })) const validator = value.validator validator.unsafeCast("test text") expect(() => validator.unsafeCast(null)).toThrowError() @@ -437,7 +425,7 @@ describe("values", () => { }) }) test("number", async () => { - const value = Value.dynamicNumber(neverWrapperDataContract, () => ({ + const value = Value.dynamicNumber(() => ({ name: "Testing", required: { default: null }, integer: false, @@ -511,7 +499,6 @@ describe("values", () => { describe("filtering", () => { test("union", async () => { const value = Value.filteredUnion( - neverWrapperDataContract, () => ["a", "c"], { name: "Testing", @@ -620,7 +607,7 @@ describe("Builder List", () => { describe("dynamic", () => { test("text", async () => { const value = Value.list( - List.dynamicText(neverWrapperDataContract, () => ({ + List.dynamicText(() => ({ name: "test", spec: { patterns: [] }, })), @@ -638,7 +625,7 @@ describe("Builder List", () => { }) test("number", async () => { const value = Value.list( - List.dynamicNumber(neverWrapperDataContract, () => ({ + List.dynamicNumber(() => ({ name: "test", spec: { integer: true }, })), diff --git a/lib/test/makeOutput.ts b/lib/test/makeOutput.ts index d4eb063..cfbae3f 100644 --- a/lib/test/makeOutput.ts +++ b/lib/test/makeOutput.ts @@ -423,7 +423,6 @@ oldSpecToBuilder( }, { // convert this to `start-sdk/lib` for conversions - startSdk: "../..", - wrapperData: "./output.wrapperData", + startSdk: "./output.sdk", }, ) diff --git a/lib/test/output.sdk.ts b/lib/test/output.sdk.ts index 74bb0bf..552b176 100644 --- a/lib/test/output.sdk.ts +++ b/lib/test/output.sdk.ts @@ -1 +1,7 @@ -export type WrapperData = {} +import { StartSDK } from "../StartSDK" + +export type WrapperData = any +export const sdk = StartSDK.of() + .withManifest() + .withStore<{ storeRoot: { storeLeaf: "value" } }>() + .build() diff --git a/lib/test/wrapperData.test.ts b/lib/test/store.test.ts similarity index 52% rename from lib/test/wrapperData.test.ts rename to lib/test/store.test.ts index 8e5078a..33dd98f 100644 --- a/lib/test/wrapperData.test.ts +++ b/lib/test/store.test.ts @@ -1,13 +1,12 @@ import { Effects } from "../types" -import { createMainUtils, utils } from "../util" -import { createWrapperDataContract } from "../wrapperData/wrapperDataContract" +import { createMainUtils } from "../util" +import { utils } from "../util/utils" type WrapperType = { config: { someValue: "a" | "b" } } -const wrapperDataContract = createWrapperDataContract() const todo = (): A => { throw new Error("not implemented") } @@ -15,97 +14,94 @@ const noop = () => {} describe("wrapperData", () => { test("types", async () => { ;async () => { - utils(wrapperDataContract, todo()).setOwnWrapperData("/config", { + utils(todo()).store.setOwn("/config", { someValue: "a", }) - utils(wrapperDataContract, todo()).setOwnWrapperData( - "/config/someValue", - "b", - ) - utils(wrapperDataContract, todo()).setOwnWrapperData("", { + utils(todo()).store.setOwn("/config/someValue", "b") + utils(todo()).store.setOwn("", { config: { someValue: "b" }, }) - utils(wrapperDataContract, todo()).setOwnWrapperData( + utils(todo()).store.setOwn( "/config/someValue", // @ts-expect-error Type is wrong for the setting value 5, ) - utils(wrapperDataContract, todo()).setOwnWrapperData( + utils(todo()).store.setOwn( // @ts-expect-error Path is wrong "/config/someVae3lue", "someValue", ) - todo().setWrapperData({ + todo().store.set({ path: "/config/someValue", value: "b", }) - todo().setWrapperData({ + todo().store.set({ //@ts-expect-error Path is wrong path: "/config/someValue", //@ts-expect-error Path is wrong value: "someValueIn", }) - todo().setWrapperData({ + todo().store.set({ //@ts-expect-error Path is wrong path: "/config/some2Value", value: "a", }) - ;(await createMainUtils(wrapperDataContract, todo()) - .getOwnWrapperData("/config/someValue") + ;(await createMainUtils(todo()) + .store.getOwn("/config/someValue") .const()) satisfies string - ;(await createMainUtils(wrapperDataContract, todo()) - .getOwnWrapperData("/config") + ;(await createMainUtils(todo()) + .store.getOwn("/config") .const()) satisfies WrapperType["config"] - await createMainUtils(wrapperDataContract, todo()) + await createMainUtils(todo()) // @ts-expect-error Path is wrong - .getOwnWrapperData("/config/somdsfeValue") + .store.getOwn("/config/somdsfeValue") .const() /// ----------------- ERRORS ----------------- - utils(wrapperDataContract, todo()).setOwnWrapperData("", { + utils(todo()).store.setOwn("", { // @ts-expect-error Type is wrong for the setting value config: { someValue: "notInAOrB" }, }) - utils(wrapperDataContract, todo()).setOwnWrapperData( + utils(todo()).store.setOwn( "/config/someValue", // @ts-expect-error Type is wrong for the setting value "notInAOrB", ) - ;(await utils(wrapperDataContract, todo()) - .getOwnWrapperData("/config/someValue") + ;(await utils(todo()) + .store.getOwn("/config/someValue") // @ts-expect-error Const should normally not be callable .const()) satisfies string - ;(await utils(wrapperDataContract, todo()) - .getOwnWrapperData("/config") + ;(await utils(todo()) + .store.getOwn("/config") // @ts-expect-error Const should normally not be callable .const()) satisfies WrapperType["config"] - await utils(wrapperDataContract, todo()) + await utils(todo()) // @ts-expect-error Path is wrong - .getOwnWrapperData("/config/somdsfeValue") + .store.getOwn("/config/somdsfeValue") // @ts-expect-error Const should normally not be callable .const() /// - ;(await utils(wrapperDataContract, todo()) - .getOwnWrapperData("/config/someValue") + ;(await utils(todo()) + .store.getOwn("/config/someValue") // @ts-expect-error satisfies type is wrong .const()) satisfies number - ;(await createMainUtils(wrapperDataContract, todo()) + ;(await createMainUtils(todo()) // @ts-expect-error Path is wrong - .getOwnWrapperData("/config/") + .store.getOwn("/config/") .const()) satisfies WrapperType["config"] - ;(await todo().getWrapperData({ + ;(await todo().store.get({ path: "/config/someValue", callback: noop, })) satisfies string - await todo().getWrapperData({ + await todo().store.get({ // @ts-expect-error Path is wrong as in it doesn't match above path: "/config/someV2alue", callback: noop, }) - await todo().getWrapperData({ + await todo().store.get({ // @ts-expect-error Path is wrong as in it doesn't exists in wrapper type path: "/config/someV2alue", callback: noop, diff --git a/lib/trigger/TriggerInput.ts b/lib/trigger/TriggerInput.ts index 6c07c71..9a52d8c 100644 --- a/lib/trigger/TriggerInput.ts +++ b/lib/trigger/TriggerInput.ts @@ -1,4 +1,4 @@ -import { HealthStatus } from "../../types" +import { HealthStatus } from "../types" export type TriggerInput = { lastResult?: HealthStatus diff --git a/lib/trigger/changeOnFirstSuccess.ts b/lib/trigger/changeOnFirstSuccess.ts index 010d2c6..28129e3 100644 --- a/lib/trigger/changeOnFirstSuccess.ts +++ b/lib/trigger/changeOnFirstSuccess.ts @@ -1,4 +1,3 @@ -import { TriggerInput } from "./TriggerInput" import { Trigger } from "./index" export function changeOnFirstSuccess(o: { diff --git a/lib/types.ts b/lib/types.ts index 1d7744a..900820e 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -251,26 +251,27 @@ export type Effects = { progress: () => Promise } - /** Get a value in a json like data, can be observed and subscribed */ - getWrapperData(options: { - /** If there is no packageId it is assumed the current package */ - packageId?: string - /** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */ - path: Path & EnsureWrapperDataPath - callback: (config: unknown, previousConfig: unknown) => void - }): Promise> + store: { + /** Get a value in a json like data, can be observed and subscribed */ + get(options: { + /** If there is no packageId it is assumed the current package */ + packageId?: string + /** The path defaults to root level, using the [JsonPath](https://jsonpath.com/) */ + path: Path & EnsureStorePath + callback: (config: unknown, previousConfig: unknown) => void + }): Promise> + /** Used to store values that can be accessed and subscribed to */ + set(options: { + /** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */ + path: Path & EnsureStorePath + value: ExtractStore + }): Promise + } getSystemSmtp(input: { callback: (config: unknown, previousConfig: unknown) => void }): Promise - /** Used to store values that can be accessed and subscribed to */ - setWrapperData(options: { - /** Sets the value for the wrapper at the path, it will override, using the [JsonPath](https://jsonpath.com/) */ - path: Path & EnsureWrapperDataPath - value: ExtractWrapperData - }): Promise - getLocalHostname(): Promise getIPHostname(): Promise /** Get the address for another service for tor interfaces */ @@ -400,20 +401,20 @@ export type Effects = { } // prettier-ignore -export type ExtractWrapperData = - Path extends `/${infer A }/${infer Rest }` ? (A extends keyof WrapperData ? ExtractWrapperData : never) : - Path extends `/${infer A }` ? (A extends keyof WrapperData ? WrapperData[A] : never) : - Path extends '' ? WrapperData : +export type ExtractStore = + Path extends `/${infer A }/${infer Rest }` ? (A extends keyof Store ? ExtractStore : never) : + Path extends `/${infer A }` ? (A extends keyof Store ? Store[A] : never) : + Path extends '' ? Store : never // prettier-ignore -type _EnsureWrapperDataPath = - Path extends`/${infer A }/${infer Rest}` ? (WrapperData extends {[K in A & string]: infer NextWrapperData} ? _EnsureWrapperDataPath : never) : - Path extends `/${infer A }` ? (WrapperData extends {[K in A]: infer B} ? Origin : never) : +type _EnsureStorePath = + Path extends`/${infer A }/${infer Rest}` ? (Store extends {[K in A & string]: infer NextStore} ? _EnsureStorePath : never) : + Path extends `/${infer A }` ? (Store extends {[K in A]: infer B} ? Origin : never) : Path extends '' ? Origin : never // prettier-ignore -export type EnsureWrapperDataPath = _EnsureWrapperDataPath +export type EnsureStorePath = _EnsureStorePath /** rsync options: https://linux.die.net/man/1/rsync */ diff --git a/lib/util/index.ts b/lib/util/index.ts index 8f68a67..ab8ee08 100644 --- a/lib/util/index.ts +++ b/lib/util/index.ts @@ -1,29 +1,12 @@ -import { Parser, string } from "ts-matches" import * as T from "../types" -import FileHelper from "./fileHelper" -import nullIfEmpty from "./nullIfEmpty" -import { GetWrapperData, getWrapperData } from "../wrapperData/getWrapperData" -import { - CheckResult, - checkPortListening, - checkWebUrl, -} from "../health/checkFns" -import { ExtractWrapperData } from "../types" -import { GetSystemSmtp } from "./GetSystemSmtp" import "./nullIfEmpty" import "./fileHelper" -import "../wrapperData/getWrapperData" +import "../store/getStore" import "./deepEqual" import "./deepMerge" import "./once" -import { LocalBinding } from "../mainFn/LocalBinding" -import { LocalPort } from "../mainFn/LocalPort" -import { NetworkBuilder } from "../mainFn/NetworkBuilder" -import { TorHostname } from "../mainFn/TorHostname" -import { DefaultString } from "../config/configTypes" -import { getDefaultString } from "./getDefaultString" -import { WrapperDataContract } from "../wrapperData/wrapperDataContract" +import { utils } from "./utils" // prettier-ignore export type FlattenIntersection = @@ -38,106 +21,9 @@ export const isKnownError = (e: unknown): e is T.KnownError => declare const affine: unique symbol -export type Utils = { - createOrUpdateVault: (opts: { - key: string - value: string | null | undefined - generator: DefaultString - }) => Promise - readFile: (fileHelper: FileHelper) => ReturnType["read"]> - writeFile: ( - fileHelper: FileHelper, - data: A, - ) => ReturnType["write"]> - getSystemSmtp: () => GetSystemSmtp & WrapperOverWrite - getWrapperData: ( - packageId: string, - path: T.EnsureWrapperDataPath, - ) => GetWrapperData & WrapperOverWrite - getOwnWrapperData: ( - path: T.EnsureWrapperDataPath, - ) => GetWrapperData & WrapperOverWrite - setOwnWrapperData: ( - path: T.EnsureWrapperDataPath, - value: ExtractWrapperData, - ) => Promise - checkPortListening( - port: number, - options: { - errorMessage: string - successMessage: string - timeoutMessage?: string - timeout?: number - }, - ): Promise - checkWebUrl( - url: string, - options?: { - timeout?: number - successMessage?: string - errorMessage?: string - }, - ): Promise - bindLan: (port: number) => Promise - networkBuilder: () => NetworkBuilder - torHostName: (id: string) => TorHostname - nullIfEmpty: typeof nullIfEmpty -} -export const utils = ( - effects: T.Effects, -): Utils => ({ - createOrUpdateVault: async ({ - key, - value, - generator, - }: { - key: string - value: string | null | undefined - generator: DefaultString - }) => { - if (value) { - await effects.vault.set({ key, value }) - return value - } - if (await effects.vault.get({ key })) { - return null - } - const newValue = getDefaultString(generator) - await effects.vault.set({ key, value: newValue }) - return newValue - }, - getSystemSmtp: () => - new GetSystemSmtp(effects) as GetSystemSmtp & WrapperOverWrite, - readFile: (fileHelper: FileHelper) => fileHelper.read(effects), - writeFile: (fileHelper: FileHelper, data: A) => - fileHelper.write(data, effects), - nullIfEmpty, - getWrapperData: ( - packageId: string, - path: T.EnsureWrapperDataPath, - ) => - getWrapperData(effects, path as any, { - packageId, - }) as any, - getOwnWrapperData: ( - path: T.EnsureWrapperDataPath, - ) => getWrapperData(effects, path as any) as any, - setOwnWrapperData: ( - path: T.EnsureWrapperDataPath, - value: ExtractWrapperData, - ) => effects.setWrapperData({ value, path: path as any }), - checkPortListening: checkPortListening.bind(null, effects), - checkWebUrl: checkWebUrl.bind(null, effects), - bindLan: async (port: number) => LocalPort.bindLan(effects, port), - networkBuilder: () => NetworkBuilder.of(effects), - torHostName: (id: string) => TorHostname.of(effects, id), -}) - export const createUtils = utils -export const createMainUtils = ( - wrapperDataContract: WrapperDataContract, - effects: T.Effects, -) => createUtils(wrapperDataContract, effects) +export const createMainUtils = (effects: T.Effects) => + createUtils(effects) type NeverPossible = { [affine]: string } export type NoAny = NeverPossible extends A diff --git a/lib/util/utils.ts b/lib/util/utils.ts new file mode 100644 index 0000000..7979ce6 --- /dev/null +++ b/lib/util/utils.ts @@ -0,0 +1,115 @@ +import * as T from "../types" +import FileHelper from "./fileHelper" +import nullIfEmpty from "./nullIfEmpty" +import { + CheckResult, + checkPortListening, + checkWebUrl, +} from "../health/checkFns" +import { ExtractStore } from "../types" +import { GetSystemSmtp } from "./GetSystemSmtp" +import { LocalBinding } from "../mainFn/LocalBinding" +import { LocalPort } from "../mainFn/LocalPort" +import { NetworkBuilder } from "../mainFn/NetworkBuilder" +import { TorHostname } from "../mainFn/TorHostname" +import { DefaultString } from "../config/configTypes" +import { getDefaultString } from "./getDefaultString" +import { GetStore, getStore } from "../store/getStore" + +export type Utils = { + createOrUpdateVault: (opts: { + key: string + value: string | null | undefined + generator: DefaultString + }) => Promise + readFile: (fileHelper: FileHelper) => ReturnType["read"]> + writeFile: ( + fileHelper: FileHelper, + data: A, + ) => ReturnType["write"]> + getSystemSmtp: () => GetSystemSmtp & WrapperOverWrite + store: { + get: ( + packageId: string, + path: T.EnsureStorePath, + ) => GetStore & WrapperOverWrite + getOwn: ( + path: T.EnsureStorePath, + ) => GetStore & WrapperOverWrite + setOwn: ( + path: T.EnsureStorePath, + value: ExtractStore, + ) => Promise + } + checkPortListening( + port: number, + options: { + errorMessage: string + successMessage: string + timeoutMessage?: string + timeout?: number + }, + ): Promise + checkWebUrl( + url: string, + options?: { + timeout?: number + successMessage?: string + errorMessage?: string + }, + ): Promise + bindLan: (port: number) => Promise + networkBuilder: () => NetworkBuilder + torHostName: (id: string) => TorHostname + nullIfEmpty: typeof nullIfEmpty +} +export const utils = ( + effects: T.Effects, +): Utils => ({ + createOrUpdateVault: async ({ + key, + value, + generator, + }: { + key: string + value: string | null | undefined + generator: DefaultString + }) => { + if (value) { + await effects.vault.set({ key, value }) + return value + } + if (await effects.vault.get({ key })) { + return null + } + const newValue = getDefaultString(generator) + await effects.vault.set({ key, value: newValue }) + return newValue + }, + getSystemSmtp: () => + new GetSystemSmtp(effects) as GetSystemSmtp & WrapperOverWrite, + readFile: (fileHelper: FileHelper) => fileHelper.read(effects), + writeFile: (fileHelper: FileHelper, data: A) => + fileHelper.write(data, effects), + nullIfEmpty, + store: { + get: ( + packageId: string, + path: T.EnsureStorePath, + ) => + getStore(effects, path as any, { + packageId, + }) as any, + getOwn: (path: T.EnsureStorePath) => + getStore(effects, path as any) as any, + setOwn: ( + path: T.EnsureStorePath, + value: ExtractStore, + ) => effects.store.set({ value, path: path as any }), + }, + checkPortListening: checkPortListening.bind(null, effects), + checkWebUrl: checkWebUrl.bind(null, effects), + bindLan: async (port: number) => LocalPort.bindLan(effects, port), + networkBuilder: () => NetworkBuilder.of(effects), + torHostName: (id: string) => TorHostname.of(effects, id), +}) diff --git a/scripts/oldSpecToBuilder.ts b/scripts/oldSpecToBuilder.ts index 1bbaf07..45d846c 100644 --- a/scripts/oldSpecToBuilder.ts +++ b/scripts/oldSpecToBuilder.ts @@ -28,19 +28,12 @@ function isString(x: unknown): x is string { export default async function makeFileContentFromOld( inputData: Promise | any, - { - startSdk = "start-sdk", - nested = true, - wrapperData = "../../wrapperData", - } = {}, + { startSdk = "start-sdk", nested = true } = {}, ) { const outputLines: string[] = [] outputLines.push(` - import { Config } from "${startSdk}/lib/config/builder/config" -import { List } from "${startSdk}/lib/config/builder/list" -import { Value } from "${startSdk}/lib/config/builder/value" -import { Variants } from "${startSdk}/lib/config/builder/variants" - import {WrapperData} from '${wrapperData}' +import { sdk } from "${startSdk}" +const {Config, List, Value, Variants} = sdk `) const data = await inputData From 715ddff896a0735212fbdd009a48667cb23c53fe Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 11:44:32 -0600 Subject: [PATCH 06/26] chore: Update to remove some wrapper data --- lib/test/output.sdk.ts | 4 ++-- lib/test/store.test.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/test/output.sdk.ts b/lib/test/output.sdk.ts index 552b176..9f2e5e7 100644 --- a/lib/test/output.sdk.ts +++ b/lib/test/output.sdk.ts @@ -1,7 +1,7 @@ import { StartSDK } from "../StartSDK" -export type WrapperData = any +export type Manifest = any export const sdk = StartSDK.of() - .withManifest() + .withManifest() .withStore<{ storeRoot: { storeLeaf: "value" } }>() .build() diff --git a/lib/test/store.test.ts b/lib/test/store.test.ts index 33dd98f..5eb43a3 100644 --- a/lib/test/store.test.ts +++ b/lib/test/store.test.ts @@ -11,7 +11,7 @@ const todo = (): A => { throw new Error("not implemented") } const noop = () => {} -describe("wrapperData", () => { +describe("Store", () => { test("types", async () => { ;async () => { utils(todo()).store.setOwn("/config", { From bc13fe06fe6957d9c4bab91a6ed96eb39e3ad07a Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:03:07 -0600 Subject: [PATCH 07/26] feat: add in the action meta metadata --- lib/StartSDK.ts | 5 +++-- lib/actions/createAction.ts | 20 +++++++++++++++++--- lib/actions/setupActions.ts | 18 +++++++++++++----- lib/manifest/ManifestTypes.ts | 1 - lib/types.ts | 5 +++++ 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/lib/StartSDK.ts b/lib/StartSDK.ts index e2427bf..68935a5 100644 --- a/lib/StartSDK.ts +++ b/lib/StartSDK.ts @@ -12,7 +12,7 @@ import { ValueSpecText, } from "./config/configTypes" import { Variants } from "./config/builder/variants" -import { createAction } from "./actions/createAction" +import { CreatedAction, createAction } from "./actions/createAction" import { ActionMetaData, Effects, @@ -200,7 +200,8 @@ export class StartSDK { }) => Promise }) => Migration.of(options), }, - setupActions, + setupActions: (...createdActions: CreatedAction[]) => + setupActions(...createdActions), setupAutoConfig: < Input, NestedConfigs extends { diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index a0cf09b..ff4ba1e 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -12,13 +12,13 @@ export class CreatedAction< Type extends Record = ExtractConfigType, > { private constructor( - public readonly myMetaData: ActionMetaData, + public readonly myMetaData: Omit, readonly fn: (options: { effects: Effects utils: Utils input: Type }) => Promise, - readonly input: Config | Config, + readonly input: Config, ) {} public validator = this.input.validator @@ -40,7 +40,11 @@ export class CreatedAction< }) => Promise, ) { const { input, ...rest } = metaData - return new CreatedAction(rest, fn, input) + return new CreatedAction( + rest, + fn, + input as Config, + ) } exportedAction: ExportedAction = ({ effects, input }) => { @@ -59,6 +63,16 @@ export class CreatedAction< }) } + async actionMetaData(options: { + effects: Effects + utils: Utils + }): Promise { + return { + ...this.myMetaData, + input: await this.input.build(options), + } + } + async getConfig({ effects }: { effects: Effects }) { return this.input.build({ effects, diff --git a/lib/actions/setupActions.ts b/lib/actions/setupActions.ts index 5efc844..a116e6b 100644 --- a/lib/actions/setupActions.ts +++ b/lib/actions/setupActions.ts @@ -1,9 +1,11 @@ -import { Effects, ExpectedExports, ExportedAction } from "../types" -import { ActionMetaData } from "../types" +import { Effects, ExpectedExports } from "../types" +import { createUtils } from "../util" import { once } from "../util/once" import { CreatedAction } from "./createAction" -export function setupActions(...createdActions: CreatedAction[]) { +export function setupActions( + ...createdActions: CreatedAction[] +) { const myActions = once(() => { const actions: Record> = {} for (const action of createdActions) { @@ -15,8 +17,14 @@ export function setupActions(...createdActions: CreatedAction[]) { get actions() { return myActions() }, - get actionsMetadata() { - return createdActions.map((x) => x.myMetaData) + async actionMetaData({ effects }: { effects: Effects }) { + const utils = createUtils(effects) + return Promise.all( + createdActions.map((x) => x.actionMetaData({ effects, utils })), + ) }, + } satisfies { + actions: ExpectedExports.actions + actionMetaData: ExpectedExports.actionMetaData } } diff --git a/lib/manifest/ManifestTypes.ts b/lib/manifest/ManifestTypes.ts index f5da303..80b91ad 100644 --- a/lib/manifest/ManifestTypes.ts +++ b/lib/manifest/ManifestTypes.ts @@ -63,7 +63,6 @@ export interface SDKManifest { containers: Record /** This denotes any data, asset, or pointer volumes that should be connected when the "docker run" command is invoked */ volumes: Record - actions: Array alerts: { install: string | null update: string | null diff --git a/lib/types.ts b/lib/types.ts index 900820e..d31f42a 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -45,6 +45,10 @@ export namespace ExpectedExports { } } + export type actionMetaData = (options: { + effects: Effects + }) => Promise> + /** * This is the entrypoint for the main container. Used to start up something like the service that the * package represents, like running a bitcoind in a bitcoind-wrapper. @@ -154,6 +158,7 @@ export type ActionMetaData = { name: string description: string id: string + input: InputSpec allowedStatuses: "only-running" | "only-stopped" | "any" /** * So the ordering of the actions is by alphabetical order of the group, then followed by the alphabetical of the actions From d2576cce1bb0e73669c0ffd56149868887f4b70e Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:05:33 -0600 Subject: [PATCH 08/26] chore: Update to fix audit --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4cfd866..e2b1626 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,7 @@ "dependencies": { "@iarna/toml": "^2.2.5", "ts-matches": "^5.4.1", - "yaml": "^2.2.1" + "yaml": "^2.2.2" }, "devDependencies": { "@types/jest": "^29.4.0", @@ -5219,9 +5219,9 @@ "dev": true }, "node_modules/yaml": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.1.tgz", - "integrity": "sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.2.2.tgz", + "integrity": "sha512-CBKFWExMn46Foo4cldiChEzn7S7SRV+wqiluAb6xmueD/fGyRHIhX8m14vVGgeFWjN540nKCNVj6P21eQjgTuA==", "engines": { "node": ">= 14" } diff --git a/package.json b/package.json index 8c35c33..c25cd26 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "dependencies": { "@iarna/toml": "^2.2.5", "ts-matches": "^5.4.1", - "yaml": "^2.2.1" + "yaml": "^2.2.2" }, "prettier": { "trailingComma": "all", From d29b855302a48d4544b3b3ca36524a1d63e92916 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:07:09 -0600 Subject: [PATCH 09/26] chore: Update the name of start sdk --- lib/{StartSDK.ts => StartSdk.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename lib/{StartSDK.ts => StartSdk.ts} (100%) diff --git a/lib/StartSDK.ts b/lib/StartSdk.ts similarity index 100% rename from lib/StartSDK.ts rename to lib/StartSdk.ts From ba3527fc4542a5e4f3d7059d95d2e9aabee912ec Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:08:04 -0600 Subject: [PATCH 10/26] chore: update something --- lib/test/output.sdk.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/test/output.sdk.ts b/lib/test/output.sdk.ts index 9f2e5e7..36b80dc 100644 --- a/lib/test/output.sdk.ts +++ b/lib/test/output.sdk.ts @@ -1,4 +1,4 @@ -import { StartSDK } from "../StartSDK" +import { StartSDK } from "../StartSdk" export type Manifest = any export const sdk = StartSDK.of() From 0c187079decb6bb14a575ce1f1031d2292b6514d Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:10:02 -0600 Subject: [PATCH 11/26] chore: Update name --- README.md | 2 +- lib/StartSdk.ts | 8 ++++---- lib/test/makeOutput.ts | 2 +- lib/test/output.sdk.ts | 4 ++-- scripts/oldSpecToBuilder.ts | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 984bdd0..d51b25b 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ ```ts { - startSdk: "start-sdk/lib", + StartSdk: "start-sdk/lib", } ``` diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 68935a5..222562d 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -56,7 +56,7 @@ type AnyNeverCond = T extends [any, ...infer U] ? AnyNeverCond : never -export class StartSDK { +export class StartSdk { private constructor() {} private anyOf( a: A, @@ -65,13 +65,13 @@ export class StartSDK { } static of() { - return new StartSDK() + return new StartSdk() } withManifest() { - return new StartSDK() + return new StartSdk() } withStore>() { - return new StartSDK() + return new StartSdk() } build() { diff --git a/lib/test/makeOutput.ts b/lib/test/makeOutput.ts index cfbae3f..cef17a7 100644 --- a/lib/test/makeOutput.ts +++ b/lib/test/makeOutput.ts @@ -423,6 +423,6 @@ oldSpecToBuilder( }, { // convert this to `start-sdk/lib` for conversions - startSdk: "./output.sdk", + StartSdk: "./output.sdk", }, ) diff --git a/lib/test/output.sdk.ts b/lib/test/output.sdk.ts index 36b80dc..a275489 100644 --- a/lib/test/output.sdk.ts +++ b/lib/test/output.sdk.ts @@ -1,7 +1,7 @@ -import { StartSDK } from "../StartSdk" +import { StartSdk } from "../StartSdk" export type Manifest = any -export const sdk = StartSDK.of() +export const sdk = StartSdk.of() .withManifest() .withStore<{ storeRoot: { storeLeaf: "value" } }>() .build() diff --git a/scripts/oldSpecToBuilder.ts b/scripts/oldSpecToBuilder.ts index 45d846c..ce8ea4e 100644 --- a/scripts/oldSpecToBuilder.ts +++ b/scripts/oldSpecToBuilder.ts @@ -28,11 +28,11 @@ function isString(x: unknown): x is string { export default async function makeFileContentFromOld( inputData: Promise | any, - { startSdk = "start-sdk", nested = true } = {}, + { StartSdk = "start-sdk", nested = true } = {}, ) { const outputLines: string[] = [] outputLines.push(` -import { sdk } from "${startSdk}" +import { sdk } from "${StartSdk}" const {Config, List, Value, Variants} = sdk `) const data = await inputData From 04fc7eaae91d4f29da765019770bb250475617f4 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:11:47 -0600 Subject: [PATCH 12/26] chore: Add type for the finnish --- lib/StartSdk.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 222562d..d1d3d81 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -48,6 +48,7 @@ import { setupMain } from "./mainFn" import { defaultTrigger } from "./trigger/defaultTrigger" import { changeOnFirstSuccess, cooldownTrigger } from "./trigger" import setupConfig, { Read, Save } from "./config/setupConfig" +export type SdkBuilt = StartSdk["build"] // prettier-ignore type AnyNeverCond = From 90d1caa3ce132fa78cf7491d9589085598ac33d3 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:15:49 -0600 Subject: [PATCH 13/26] chore: Update the build to ensure the correct shape --- lib/StartSdk.ts | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index d1d3d81..7b0333a 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -48,7 +48,6 @@ import { setupMain } from "./mainFn" import { defaultTrigger } from "./trigger/defaultTrigger" import { changeOnFirstSuccess, cooldownTrigger } from "./trigger" import setupConfig, { Read, Save } from "./config/setupConfig" -export type SdkBuilt = StartSdk["build"] // prettier-ignore type AnyNeverCond = @@ -59,12 +58,6 @@ type AnyNeverCond = export class StartSdk { private constructor() {} - private anyOf( - a: A, - ): AnyNeverCond<[Manifest, Store], "Build not ready", A> { - return a as any - } - static of() { return new StartSdk() } @@ -75,8 +68,8 @@ export class StartSdk { return new StartSdk() } - build() { - return this.anyOf({ + build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) { + return { AutoConfig: ( configs: AutoConfigFrom, path: keyof AutoConfigFrom, @@ -416,6 +409,6 @@ export class StartSdk { a: VariantValues, ) => Variants.of(a), }, - }) + } } } From f5f858123309ae74b6179ba1022959d92bfc52ec Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:22:40 -0600 Subject: [PATCH 14/26] chore: Update migrations with manifest --- lib/StartSdk.ts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 7b0333a..438f724 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -1,4 +1,3 @@ -import { AnyParser } from "ts-matches" import { ManifestVersion, SDKManifest } from "./manifest/ManifestTypes" import { RequiredDefault, Value } from "./config/builder/value" import { Config, ExtractConfigType, LazyBuild } from "./config/builder/config" @@ -57,15 +56,15 @@ type AnyNeverCond = never export class StartSdk { - private constructor() {} + private constructor(readonly manifest: Manifest) {} static of() { - return new StartSdk() + return new StartSdk(null as never) } - withManifest() { - return new StartSdk() + withManifest(manifest: Manifest) { + return new StartSdk(manifest) } withStore>() { - return new StartSdk() + return new StartSdk(this.manifest) } build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) { @@ -231,9 +230,8 @@ export class StartSdk { }) => Promise>, ) => setupMain(fn), setupMigrations: >>( - manifest: SDKManifest, ...migrations: EnsureUniqueId - ) => setupMigrations(manifest, ...migrations), + ) => setupMigrations(this.manifest, ...migrations), setupUninstall: (fn: UninstallFn) => setupUninstall(fn), trigger: { defaultTrigger, From 0ff462a74414c790f77d44574265e73f076528d6 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:25:51 -0600 Subject: [PATCH 15/26] chore: Update the migration of --- lib/inits/migrations/Migration.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/inits/migrations/Migration.ts b/lib/inits/migrations/Migration.ts index 5723f8c..15d23ac 100644 --- a/lib/inits/migrations/Migration.ts +++ b/lib/inits/migrations/Migration.ts @@ -15,7 +15,7 @@ export class Migration { up: (opts: { effects: Effects; utils: Utils }) => Promise down: (opts: { effects: Effects; utils: Utils }) => Promise }) { - return new Migration(options) + return new Migration(options) } async up(opts: { effects: Effects; utils: Utils }) { From 021c4d4503f02c6d7814f9c9614e2fd93a8142c0 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 14:36:50 -0600 Subject: [PATCH 16/26] chore: Update the config type thank you --- lib/actions/setupActions.ts | 4 ++-- lib/inits/migrations/setupMigrations.ts | 2 +- lib/test/output.sdk.ts | 4 ++-- lib/types.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/actions/setupActions.ts b/lib/actions/setupActions.ts index a116e6b..aa095b4 100644 --- a/lib/actions/setupActions.ts +++ b/lib/actions/setupActions.ts @@ -17,7 +17,7 @@ export function setupActions( get actions() { return myActions() }, - async actionMetaData({ effects }: { effects: Effects }) { + async actionsMetaData({ effects }: { effects: Effects }) { const utils = createUtils(effects) return Promise.all( createdActions.map((x) => x.actionMetaData({ effects, utils })), @@ -25,6 +25,6 @@ export function setupActions( }, } satisfies { actions: ExpectedExports.actions - actionMetaData: ExpectedExports.actionMetaData + actionsMetaData: ExpectedExports.actionsMetaData } } diff --git a/lib/inits/migrations/setupMigrations.ts b/lib/inits/migrations/setupMigrations.ts index 7beb4de..8ca7453 100644 --- a/lib/inits/migrations/setupMigrations.ts +++ b/lib/inits/migrations/setupMigrations.ts @@ -60,7 +60,7 @@ export function setupMigrations< Store, Migrations extends Array>, >(manifest: SDKManifest, ...migrations: EnsureUniqueId) { - return Migrations.of(manifest, ...migrations) + return Migrations.of(manifest, ...migrations) } // prettier-ignore diff --git a/lib/test/output.sdk.ts b/lib/test/output.sdk.ts index a275489..a69ccb8 100644 --- a/lib/test/output.sdk.ts +++ b/lib/test/output.sdk.ts @@ -2,6 +2,6 @@ import { StartSdk } from "../StartSdk" export type Manifest = any export const sdk = StartSdk.of() - .withManifest() + .withManifest({} as any) .withStore<{ storeRoot: { storeLeaf: "value" } }>() - .build() + .build(true) diff --git a/lib/types.ts b/lib/types.ts index d31f42a..2176a88 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -45,7 +45,7 @@ export namespace ExpectedExports { } } - export type actionMetaData = (options: { + export type actionsMetaData = (options: { effects: Effects }) => Promise> From 86cee9e7886dc39968265ca9fc9f1e4b7ec83e86 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 15:10:28 -0600 Subject: [PATCH 17/26] feat: Auto config figure out type --- lib/StartSdk.ts | 13 +++++++++---- lib/autoconfig/AutoConfig.ts | 32 +++++++++++++++++++++---------- lib/autoconfig/setupAutoConfig.ts | 18 ++++++++++------- 3 files changed, 42 insertions(+), 21 deletions(-) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 438f724..2ec771d 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -69,7 +69,7 @@ export class StartSdk { build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) { return { - AutoConfig: ( + AutoConfig: >( configs: AutoConfigFrom, path: keyof AutoConfigFrom, ) => new AutoConfig(configs, path), @@ -196,13 +196,18 @@ export class StartSdk { setupActions: (...createdActions: CreatedAction[]) => setupActions(...createdActions), setupAutoConfig: < - Input, + Input extends Record, NestedConfigs extends { [key in keyof Manifest["dependencies"]]: unknown }, >( - configs: AutoConfigFrom, - ) => setupAutoConfig(configs), + config: Config, + autoConfigs: AutoConfigFrom, + ) => + setupAutoConfig( + config, + autoConfigs, + ), setupBackups: (...args: SetupBackupsParams) => setupBackups(...args), setupConfig: < diff --git a/lib/autoconfig/AutoConfig.ts b/lib/autoconfig/AutoConfig.ts index 590036a..e6ff02d 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/autoconfig/AutoConfig.ts @@ -2,16 +2,28 @@ import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util/utils" import { deepEqual } from "../util/deepEqual" import { deepMerge } from "../util/deepMerge" +import { Config } from "../config/builder/config" -export type AutoConfigFrom = { - [key in keyof NestedConfigs & string]: (options: { - effects: Effects - localConfig: Input - remoteConfig: NestedConfigs[key] - utils: Utils - }) => Promise> +export type AutoConfigFrom< + Store, + Input, + NestedConfigs extends Record, +> = { + [key in keyof NestedConfigs & string]: { + serviceConfig: Config + autoConfig: (options: { + effects: Effects + localConfig: Input + remoteConfig: NestedConfigs[key] + utils: Utils + }) => Promise> + } } -export class AutoConfig { +export class AutoConfig< + Store, + Input, + NestedConfigs extends Record, +> { constructor( readonly configs: AutoConfigFrom, readonly path: keyof AutoConfigFrom, @@ -33,7 +45,7 @@ export class AutoConfig { deepMerge( {}, options.localConfig, - await this.configs[this.path](newOptions), + await this.configs[this.path].autoConfig(newOptions), ), ) ) @@ -51,7 +63,7 @@ export class AutoConfig { return deepMerge( {}, options.localConfig, - await this.configs[this.path](newOptions), + await this.configs[this.path].autoConfig(newOptions), ) } } diff --git a/lib/autoconfig/setupAutoConfig.ts b/lib/autoconfig/setupAutoConfig.ts index 9258acd..a501ebc 100644 --- a/lib/autoconfig/setupAutoConfig.ts +++ b/lib/autoconfig/setupAutoConfig.ts @@ -1,24 +1,28 @@ +import { Config } from "../config/builder/config" import { SDKManifest } from "../manifest/ManifestTypes" import { AutoConfig, AutoConfigFrom } from "./AutoConfig" export function setupAutoConfig< Store, - Input, + Input extends Record, Manifest extends SDKManifest, NestedConfigs extends { [key in keyof Manifest["dependencies"]]: unknown }, ->(configs: AutoConfigFrom) { - type C = typeof configs - const answer = { ...configs } as unknown as { +>( + config: Config, + autoConfigs: AutoConfigFrom, +) { + type C = typeof autoConfigs + const answer = { ...autoConfigs } as unknown as { [k in keyof C]: AutoConfig } - for (const key in configs) { - answer[key as keyof typeof configs] = new AutoConfig< + for (const key in autoConfigs) { + answer[key as keyof typeof autoConfigs] = new AutoConfig< Store, Input, NestedConfigs - >(configs, key as keyof typeof configs) + >(autoConfigs, key as keyof typeof autoConfigs) } return answer } From f8a63f6e385fb4be55eeb03e7e72bf5c5b7eaac3 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 15:55:19 -0600 Subject: [PATCH 18/26] feat: Add vault through utils + sdk --- lib/StartSdk.ts | 142 ++++++++------ lib/actions/createAction.ts | 24 +-- lib/actions/setupActions.ts | 8 +- lib/autoconfig/AutoConfig.ts | 14 +- lib/autoconfig/setupAutoConfig.ts | 8 +- lib/config/builder/config.ts | 45 +++-- lib/config/builder/list.ts | 26 +-- lib/config/builder/value.ts | 245 +++++++++++++----------- lib/config/builder/variants.ts | 14 +- lib/config/configConstants.ts | 2 +- lib/config/setupConfig.ts | 27 +-- lib/inits/migrations/Migration.ts | 30 ++- lib/inits/migrations/setupMigrations.ts | 32 ++-- lib/inits/setupInit.ts | 8 +- lib/inits/setupInstall.ts | 12 +- lib/inits/setupUninstall.ts | 12 +- lib/mainFn/index.ts | 6 +- lib/store/getStore.ts | 2 - lib/test/output.sdk.ts | 1 + lib/test/store.test.ts | 47 ++--- lib/types.ts | 2 +- lib/util/index.ts | 4 +- lib/util/utils.ts | 27 ++- 23 files changed, 427 insertions(+), 311 deletions(-) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 2ec771d..833d2b3 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -55,24 +55,29 @@ type AnyNeverCond = T extends [any, ...infer U] ? AnyNeverCond : never -export class StartSdk { +export class StartSdk { private constructor(readonly manifest: Manifest) {} static of() { - return new StartSdk(null as never) + return new StartSdk(null as never) } withManifest(manifest: Manifest) { - return new StartSdk(manifest) + return new StartSdk(manifest) } withStore>() { - return new StartSdk(this.manifest) + return new StartSdk(this.manifest) + } + withVault>() { + return new StartSdk(this.manifest) } - build(isReady: AnyNeverCond<[Manifest, Store], "Build not ready", true>) { + build( + isReady: AnyNeverCond<[Manifest, Store, Vault], "Build not ready", true>, + ) { return { AutoConfig: >( - configs: AutoConfigFrom, - path: keyof AutoConfigFrom, - ) => new AutoConfig(configs, path), + configs: AutoConfigFrom, + path: keyof AutoConfigFrom, + ) => new AutoConfig(configs, path), Backups: { volumes: (...volumeNames: Array) => Backups.volumes(...volumeNames), @@ -84,29 +89,32 @@ export class StartSdk { }, Config: { of: < - Spec extends Record | Value>, + Spec extends Record< + string, + Value | Value + >, >( spec: Spec, - ) => Config.of(spec), + ) => Config.of(spec), }, configConstants: { smtpConfig }, createAction: < Store, ConfigType extends | Record - | Config - | Config, + | Config + | Config, Type extends Record = ExtractConfigType, >( metaData: Omit & { - input: Config | Config + input: Config | Config }, fn: (options: { effects: Effects - utils: Utils + utils: Utils input: Type }) => Promise, - ) => createAction(metaData, fn), + ) => createAction(metaData, fn), Daemons: { of: Daemons.of }, healthCheck: { checkPortListening, @@ -128,14 +136,15 @@ export class StartSdk { maxLength?: number | null }, aSpec: { - spec: Config + spec: Config displayAs?: null | string uniqueBy?: null | UniqueBy }, - ) => List.obj(a, aSpec), + ) => List.obj(a, aSpec), dynamicText: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -158,10 +167,11 @@ export class StartSdk { } } >, - ) => List.dynamicText(getA), + ) => List.dynamicText(getA), dynamicNumber: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -181,30 +191,33 @@ export class StartSdk { } } >, - ) => List.dynamicNumber(getA), + ) => List.dynamicNumber(getA), }, Migration: { of: (options: { version: Version - up: (opts: { effects: Effects; utils: Utils }) => Promise + up: (opts: { + effects: Effects + utils: Utils + }) => Promise down: (opts: { effects: Effects - utils: Utils + utils: Utils }) => Promise - }) => Migration.of(options), + }) => Migration.of(options), }, - setupActions: (...createdActions: CreatedAction[]) => - setupActions(...createdActions), + setupActions: (...createdActions: CreatedAction[]) => + setupActions(...createdActions), setupAutoConfig: < Input extends Record, NestedConfigs extends { [key in keyof Manifest["dependencies"]]: unknown }, >( - config: Config, - autoConfigs: AutoConfigFrom, + config: Config, + autoConfigs: AutoConfigFrom, ) => - setupAutoConfig( + setupAutoConfig( config, autoConfigs, ), @@ -213,31 +226,38 @@ export class StartSdk { setupConfig: < ConfigType extends | Record - | Config - | Config, + | Config + | Config, Type extends Record = ExtractConfigType, >( - spec: Config | Config, - write: Save, - read: Read, - ) => setupConfig(spec, write, read), + spec: Config | Config, + write: Save, + read: Read, + ) => + setupConfig( + spec, + write, + read, + ), setupInit: ( - migrations: Migrations, - install: Install, - uninstall: Uninstall, - ) => setupInit(migrations, install, uninstall), - setupInstall: (fn: InstallFn) => Install.of(fn), + migrations: Migrations, + install: Install, + uninstall: Uninstall, + ) => setupInit(migrations, install, uninstall), + setupInstall: (fn: InstallFn) => Install.of(fn), setupMain: ( fn: (o: { effects: Effects started(onTerm: () => void): null - utils: Utils + utils: Utils }) => Promise>, - ) => setupMain(fn), - setupMigrations: >>( + ) => setupMain(fn), + setupMigrations: >>( ...migrations: EnsureUniqueId - ) => setupMigrations(this.manifest, ...migrations), - setupUninstall: (fn: UninstallFn) => setupUninstall(fn), + ) => + setupMigrations(this.manifest, ...migrations), + setupUninstall: (fn: UninstallFn) => + setupUninstall(fn), trigger: { defaultTrigger, cooldownTrigger, @@ -258,6 +278,7 @@ export class StartSdk { dynamicToggle: ( a: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -266,10 +287,11 @@ export class StartSdk { disabled?: false | string } >, - ) => Value.dynamicToggle(a), + ) => Value.dynamicToggle(a), dynamicText: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -287,10 +309,11 @@ export class StartSdk { generate?: null | RandomString } >, - ) => Value.dynamicText(getA), + ) => Value.dynamicText(getA), dynamicTextarea: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -303,10 +326,11 @@ export class StartSdk { generate?: null | RandomString } >, - ) => Value.dynamicTextarea(getA), + ) => Value.dynamicTextarea(getA), dynamicNumber: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -322,10 +346,11 @@ export class StartSdk { disabled?: false | string } >, - ) => Value.dynamicNumber(getA), + ) => Value.dynamicNumber(getA), dynamicColor: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -335,10 +360,11 @@ export class StartSdk { disabled?: false | string } >, - ) => Value.dynamicColor(getA), + ) => Value.dynamicColor(getA), dynamicDatetime: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -352,10 +378,11 @@ export class StartSdk { disabled?: false | string } >, - ) => Value.dynamicDatetime(getA), + ) => Value.dynamicDatetime(getA), dynamicSelect: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -365,10 +392,11 @@ export class StartSdk { disabled?: false | string } >, - ) => Value.dynamicSelect(getA), + ) => Value.dynamicSelect(getA), dynamicMultiselect: ( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -380,21 +408,23 @@ export class StartSdk { disabled?: false | string } >, - ) => Value.dynamicMultiselect(getA), + ) => Value.dynamicMultiselect(getA), filteredUnion: < Required extends RequiredDefault, Type extends Record, >( - getDisabledFn: LazyBuild, + getDisabledFn: LazyBuild, a: { name: string description?: string | null warning?: string | null required: Required }, - aVariants: Variants | Variants, + aVariants: + | Variants + | Variants, ) => - Value.filteredUnion( + Value.filteredUnion( getDisabledFn, a, aVariants, @@ -405,12 +435,12 @@ export class StartSdk { VariantValues extends { [K in string]: { name: string - spec: Config + spec: Config } }, >( a: VariantValues, - ) => Variants.of(a), + ) => Variants.of(a), }, } } diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index ff4ba1e..7a9a7c5 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -5,45 +5,47 @@ import { Utils, utils } from "../util/utils" export class CreatedAction< Store, + Vault, ConfigType extends | Record - | Config - | Config, + | Config + | Config, Type extends Record = ExtractConfigType, > { private constructor( public readonly myMetaData: Omit, readonly fn: (options: { effects: Effects - utils: Utils + utils: Utils input: Type }) => Promise, - readonly input: Config, + readonly input: Config, ) {} public validator = this.input.validator static of< Store, + Vault, ConfigType extends | Record - | Config - | Config, + | Config + | Config, Type extends Record = ExtractConfigType, >( metaData: Omit & { - input: Config | Config + input: Config | Config }, fn: (options: { effects: Effects - utils: Utils + utils: Utils input: Type }) => Promise, ) { const { input, ...rest } = metaData - return new CreatedAction( + return new CreatedAction( rest, fn, - input as Config, + input as Config, ) } @@ -65,7 +67,7 @@ export class CreatedAction< async actionMetaData(options: { effects: Effects - utils: Utils + utils: Utils }): Promise { return { ...this.myMetaData, diff --git a/lib/actions/setupActions.ts b/lib/actions/setupActions.ts index aa095b4..f2230ed 100644 --- a/lib/actions/setupActions.ts +++ b/lib/actions/setupActions.ts @@ -3,11 +3,11 @@ import { createUtils } from "../util" import { once } from "../util/once" import { CreatedAction } from "./createAction" -export function setupActions( - ...createdActions: CreatedAction[] +export function setupActions( + ...createdActions: CreatedAction[] ) { const myActions = once(() => { - const actions: Record> = {} + const actions: Record> = {} for (const action of createdActions) { actions[action.myMetaData.id] = action } @@ -18,7 +18,7 @@ export function setupActions( return myActions() }, async actionsMetaData({ effects }: { effects: Effects }) { - const utils = createUtils(effects) + const utils = createUtils(effects) return Promise.all( createdActions.map((x) => x.actionMetaData({ effects, utils })), ) diff --git a/lib/autoconfig/AutoConfig.ts b/lib/autoconfig/AutoConfig.ts index e6ff02d..484f3bb 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/autoconfig/AutoConfig.ts @@ -6,27 +6,29 @@ import { Config } from "../config/builder/config" export type AutoConfigFrom< Store, + Vault, Input, NestedConfigs extends Record, > = { [key in keyof NestedConfigs & string]: { - serviceConfig: Config + serviceConfig: Config autoConfig: (options: { effects: Effects localConfig: Input remoteConfig: NestedConfigs[key] - utils: Utils + utils: Utils }) => Promise> } } export class AutoConfig< Store, + Vault, Input, NestedConfigs extends Record, > { constructor( - readonly configs: AutoConfigFrom, - readonly path: keyof AutoConfigFrom, + readonly configs: AutoConfigFrom, + readonly path: keyof AutoConfigFrom, ) {} async check( @@ -35,7 +37,7 @@ export class AutoConfig< const origConfig = JSON.parse(JSON.stringify(options.localConfig)) const newOptions = { ...options, - utils: utils(options.effects), + utils: utils(options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, } @@ -56,7 +58,7 @@ export class AutoConfig< ): ReturnType { const newOptions = { ...options, - utils: utils(options.effects), + utils: utils(options.effects), localConfig: options.localConfig as Input, remoteConfig: options.remoteConfig as any, } diff --git a/lib/autoconfig/setupAutoConfig.ts b/lib/autoconfig/setupAutoConfig.ts index a501ebc..6055929 100644 --- a/lib/autoconfig/setupAutoConfig.ts +++ b/lib/autoconfig/setupAutoConfig.ts @@ -4,22 +4,24 @@ import { AutoConfig, AutoConfigFrom } from "./AutoConfig" export function setupAutoConfig< Store, + Vault, Input extends Record, Manifest extends SDKManifest, NestedConfigs extends { [key in keyof Manifest["dependencies"]]: unknown }, >( - config: Config, - autoConfigs: AutoConfigFrom, + _config: Config, + autoConfigs: AutoConfigFrom, ) { type C = typeof autoConfigs const answer = { ...autoConfigs } as unknown as { - [k in keyof C]: AutoConfig + [k in keyof C]: AutoConfig } for (const key in autoConfigs) { answer[key as keyof typeof autoConfigs] = new AutoConfig< Store, + Vault, Input, NestedConfigs >(autoConfigs, key as keyof typeof autoConfigs) diff --git a/lib/config/builder/config.ts b/lib/config/builder/config.ts index 8f2e1ba..e9cd9fd 100644 --- a/lib/config/builder/config.ts +++ b/lib/config/builder/config.ts @@ -5,24 +5,28 @@ import { _ } from "../../util" import { Effects } from "../../types" import { Parser, object } from "ts-matches" -export type LazyBuildOptions = { +export type LazyBuildOptions = { effects: Effects - utils: Utils + utils: Utils } -export type LazyBuild = ( - options: LazyBuildOptions, +export type LazyBuild = ( + options: LazyBuildOptions, ) => Promise | ExpectedOut // prettier-ignore -export type ExtractConfigType | Config, any> | Config, never>> = - A extends Config | Config ? B : +export type ExtractConfigType | Config, any, any> | Config, never, never>> = + A extends Config | Config ? B : A -export type ConfigSpecOf, Store = never> = { - [K in keyof A]: Value +export type ConfigSpecOf< + A extends Record, + Store = never, + Vault = never, +> = { + [K in keyof A]: Value } -export type MaybeLazyValues = LazyBuild | A +export type MaybeLazyValues = LazyBuild | 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, Store> { +export class Config, Store, Vault> { private constructor( private readonly spec: { - [K in keyof Type]: Value | Value + [K in keyof Type]: + | Value + | Value }, public validator: Parser, ) {} - async build(options: LazyBuildOptions) { + async build(options: LazyBuildOptions) { const answer = {} as { [K in keyof Type]: ValueSpec } @@ -97,8 +103,12 @@ export class Config, Store> { } static of< - Spec extends Record | Value>, + Spec extends Record< + string, + Value | Value + >, Store, + Vault, >(spec: Spec) { const validatorObj = {} as { [K in keyof Spec]: Parser @@ -110,12 +120,13 @@ export class Config, Store> { return new Config< { [K in keyof Spec]: Spec[K] extends - | Value - | Value + | Value + | Value ? T : never }, - Store + Store, + Vault >(spec, validator as any) } @@ -134,6 +145,6 @@ export class Config, Store> { ``` */ withStore() { - return this as any as Config + return this as any as Config } } diff --git a/lib/config/builder/list.ts b/lib/config/builder/list.ts index 2b8c2b4..e31e623 100644 --- a/lib/config/builder/list.ts +++ b/lib/config/builder/list.ts @@ -22,9 +22,9 @@ export const authorizationList = List.string({ export const auth = Value.list(authorizationList); ``` */ -export class List { +export class List { private constructor( - public build: LazyBuild, + public build: LazyBuild, public validator: Parser, ) {} static text( @@ -49,7 +49,7 @@ export class List { generate?: null | RandomString }, ) { - return new List(() => { + return new List(() => { const spec = { type: "text" as const, placeholder: null, @@ -73,9 +73,10 @@ export class List { } satisfies ValueSpecListOf<"text"> }, arrayOf(string)) } - static dynamicText( + static dynamicText( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -99,7 +100,7 @@ export class List { } >, ) { - return new List(async (options) => { + return new List(async (options) => { const { spec: aSpec, ...a } = await getA(options) const spec = { type: "text" as const, @@ -143,7 +144,7 @@ export class List { placeholder?: string | null }, ) { - return new List(() => { + return new List(() => { const spec = { type: "number" as const, placeholder: null, @@ -166,9 +167,10 @@ export class List { } satisfies ValueSpecListOf<"number"> }, arrayOf(number)) } - static dynamicNumber( + static dynamicNumber( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -189,7 +191,7 @@ export class List { } >, ) { - return new List(async (options) => { + return new List(async (options) => { const { spec: aSpec, ...a } = await getA(options) const spec = { type: "number" as const, @@ -213,7 +215,7 @@ export class List { } }, arrayOf(number)) } - static obj, Store>( + static obj, Store, Vault>( a: { name: string description?: string | null @@ -224,12 +226,12 @@ export class List { maxLength?: number | null }, aSpec: { - spec: Config + spec: Config displayAs?: null | string uniqueBy?: null | UniqueBy }, ) { - return new List(async (options) => { + return new List(async (options) => { const { spec: previousSpecSpec, ...restSpec } = aSpec const specSpec = await previousSpecSpec.build(options) const spec = { @@ -271,6 +273,6 @@ export class List { ``` */ withStore() { - return this as any as List + return this as any as List } } diff --git a/lib/config/builder/value.ts b/lib/config/builder/value.ts index 7d1963e..315e378 100644 --- a/lib/config/builder/value.ts +++ b/lib/config/builder/value.ts @@ -94,9 +94,9 @@ const username = Value.string({ }); ``` */ -export class Value { +export class Value { protected constructor( - public build: LazyBuild, + public build: LazyBuild, public validator: Parser, ) {} static toggle(a: { @@ -108,7 +108,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value( + return new Value( async () => ({ description: null, warning: null, @@ -120,9 +120,10 @@ export class Value { boolean, ) } - static dynamicToggle( + static dynamicToggle( a: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -132,7 +133,7 @@ export class Value { } >, ) { - return new Value( + return new Value( async (options) => ({ description: null, warning: null, @@ -163,7 +164,7 @@ export class Value { immutable?: boolean generate?: null | RandomString }) { - return new Value, never>( + return new Value, never, never>( async () => ({ type: "text" as const, description: null, @@ -183,9 +184,10 @@ export class Value { asRequiredParser(string, a), ) } - static dynamicText( + static dynamicText( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -204,25 +206,28 @@ export class Value { } >, ) { - return new Value(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( + 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 { immutable?: boolean generate?: null | RandomString }) { - return new Value( + return new Value( async () => ({ description: null, @@ -254,9 +259,10 @@ export class Value { string, ) } - static dynamicTextarea( + static dynamicTextarea( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -270,7 +276,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { description: null, @@ -302,7 +308,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, never>( + return new Value, never, never>( () => ({ type: "number" as const, description: null, @@ -320,9 +326,10 @@ export class Value { asRequiredParser(number, a), ) } - static dynamicNumber( + static dynamicNumber( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -339,23 +346,26 @@ export class Value { } >, ) { - return new Value(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( + 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>(a: { name: string @@ -366,7 +376,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, never>( + return new Value, never, never>( () => ({ type: "color" as const, description: null, @@ -381,9 +391,10 @@ export class Value { ) } - static dynamicColor( + static dynamicColor( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -394,18 +405,21 @@ export class Value { } >, ) { - return new Value(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( + 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>(a: { name: string @@ -421,7 +435,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, never>( + return new Value, never, never>( () => ({ type: "datetime" as const, description: null, @@ -438,9 +452,10 @@ export class Value { asRequiredParser(string, a), ) } - static dynamicDatetime( + static dynamicDatetime( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -455,22 +470,25 @@ export class Value { } >, ) { - return new Value(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( + 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, @@ -485,7 +503,7 @@ export class Value { Default is false */ immutable?: boolean }) { - return new Value, never>( + return new Value, never, never>( () => ({ description: null, warning: null, @@ -503,9 +521,10 @@ export class Value { ) as any, ) } - static dynamicSelect( + static dynamicSelect( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -516,18 +535,21 @@ export class Value { } >, ) { - return new Value(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( + 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>(a: { name: string @@ -541,7 +563,7 @@ export class Value { 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 { ), ) } - static dynamicMultiselect( + static dynamicMultiselect( getA: LazyBuild< Store, + Vault, { name: string description?: string | null @@ -572,7 +595,7 @@ export class Value { } >, ) { - return new Value(async (options) => { + return new Value(async (options) => { const a = await getA(options) return { type: "multiselect" as const, @@ -586,15 +609,15 @@ export class Value { } }, arrayOf(string)) } - static object, Store>( + static object, Store, Vault>( a: { name: string description?: string | null warning?: string | null }, - previousSpec: Config, + previousSpec: Config, ) { - return new Value(async (options) => { + return new Value(async (options) => { const spec = await previousSpec.build(options as any) return { type: "object" as const, @@ -605,7 +628,7 @@ export class Value { } }, previousSpec.validator) } - static union, Type, Store>( + static union, Type, Store, Vault>( a: { name: string description?: string | null @@ -615,9 +638,9 @@ export class Value { Default is false */ immutable?: boolean }, - aVariants: Variants, + aVariants: Variants, ) { - return new Value, Store>( + return new Value, Store, Vault>( async (options) => ({ type: "union" as const, description: null, @@ -634,17 +657,18 @@ export class Value { Required extends RequiredDefault, Type extends Record, Store = never, + Vault = never, >( - getDisabledFn: LazyBuild, + getDisabledFn: LazyBuild, a: { name: string description?: string | null warning?: string | null required: Required }, - aVariants: Variants | Variants, + aVariants: Variants | Variants, ) { - return new Value, Store>( + return new Value, Store, Vault>( async (options) => ({ type: "union" as const, description: null, @@ -659,8 +683,11 @@ export class Value { ) } - static list(a: List) { - return new Value((options) => a.build(options), a.validator) + static list(a: List) { + return new Value( + (options) => a.build(options), + a.validator, + ) } /** @@ -678,6 +705,6 @@ export class Value { ``` */ withStore() { - return this as any as Value + return this as any as Value } } diff --git a/lib/config/builder/variants.ts b/lib/config/builder/variants.ts index 01f11be..06ee57c 100644 --- a/lib/config/builder/variants.ts +++ b/lib/config/builder/variants.ts @@ -51,20 +51,21 @@ export const pruning = Value.union( ); ``` */ -export class Variants { +export class Variants { static text: any private constructor( - public build: LazyBuild, + public build: LazyBuild, public validator: Parser, ) {} static of< VariantValues extends { [K in string]: { name: string - spec: Config | Config + spec: Config | Config } }, Store, + Vault, >(a: VariantValues) { const validator = anyOf( ...Object.entries(a).map(([name, { spec }]) => @@ -81,11 +82,12 @@ export class Variants { unionSelectKey: K // prettier-ignore unionValueKey: - VariantValues[K]["spec"] extends (Config | Config) ? B : + VariantValues[K]["spec"] extends (Config | Config) ? 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 { ``` */ withStore() { - return this as any as Variants + return this as any as Variants } } diff --git a/lib/config/configConstants.ts b/lib/config/configConstants.ts index bddb668..54e0e62 100644 --- a/lib/config/configConstants.ts +++ b/lib/config/configConstants.ts @@ -18,7 +18,7 @@ export const smtpConfig = Value.filteredUnion( system: { name: "System Credentials", spec: Config.of({}) }, custom: { name: "Custom Credentials", - spec: Config.of, never>({ + spec: Config.of, never, never>({ server: Value.text({ name: "SMTP Server", required: { diff --git a/lib/config/setupConfig.ts b/lib/config/setupConfig.ts index cfd1979..50cb93b 100644 --- a/lib/config/setupConfig.ts +++ b/lib/config/setupConfig.ts @@ -12,15 +12,16 @@ export type DependenciesReceipt = void & { export type Save< Store, + Vault, A extends | Record - | Config, any> - | Config, never>, + | Config, any, any> + | Config, never, never>, Manifest extends SDKManifest, > = (options: { effects: Effects input: ExtractConfigType & Record - utils: Utils + utils: Utils dependencies: D.ConfigDependencies }) => Promise<{ dependenciesReceipt: DependenciesReceipt @@ -28,13 +29,14 @@ export type Save< }> export type Read< Store, + Vault, A extends | Record - | Config, any> - | Config, never>, + | Config, any, any> + | Config, never, never>, > = (options: { effects: Effects - utils: Utils + utils: Utils }) => Promise & Record)> /** * 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 - | Config - | Config, + | Config + | Config, Manifest extends SDKManifest, Type extends Record = ExtractConfigType, >( - spec: Config | Config, - write: Save, - read: Read, + spec: Config | Config, + write: Save, + read: Read, ) { const validator = spec.validator return { @@ -74,7 +77,7 @@ export function setupConfig< } }) as ExpectedExports.setConfig, getConfig: (async ({ effects }) => { - const myUtils = utils(effects) + const myUtils = utils(effects) const configValue = nullIfEmpty( (await read({ effects, utils: myUtils })) || null, ) diff --git a/lib/inits/migrations/Migration.ts b/lib/inits/migrations/Migration.ts index 15d23ac..2aed622 100644 --- a/lib/inits/migrations/Migration.ts +++ b/lib/inits/migrations/Migration.ts @@ -2,27 +2,39 @@ import { ManifestVersion } from "../../manifest/ManifestTypes" import { Effects } from "../../types" import { Utils } from "../../util/utils" -export class Migration { +export class Migration { constructor( readonly options: { version: Version - up: (opts: { effects: Effects; utils: Utils }) => Promise - down: (opts: { effects: Effects; utils: Utils }) => Promise + up: (opts: { + effects: Effects + utils: Utils + }) => Promise + down: (opts: { + effects: Effects + utils: Utils + }) => Promise }, ) {} - static of(options: { + static of(options: { version: Version - up: (opts: { effects: Effects; utils: Utils }) => Promise - down: (opts: { effects: Effects; utils: Utils }) => Promise + up: (opts: { + effects: Effects + utils: Utils + }) => Promise + down: (opts: { + effects: Effects + utils: Utils + }) => Promise }) { - return new Migration(options) + return new Migration(options) } - async up(opts: { effects: Effects; utils: Utils }) { + async up(opts: { effects: Effects; utils: Utils }) { this.up(opts) } - async down(opts: { effects: Effects; utils: Utils }) { + async down(opts: { effects: Effects; utils: Utils }) { this.down(opts) } } diff --git a/lib/inits/migrations/setupMigrations.ts b/lib/inits/migrations/setupMigrations.ts index 8ca7453..a7278c7 100644 --- a/lib/inits/migrations/setupMigrations.ts +++ b/lib/inits/migrations/setupMigrations.ts @@ -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 { +export class Migrations { private constructor( readonly manifest: SDKManifest, - readonly migrations: Array>, + readonly migrations: Array>, ) {} private sortedMigrations = once(() => { const migrationsAsVersions = ( - this.migrations as Array> + this.migrations as Array> ).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>>( - manifest: SDKManifest, - ...migrations: EnsureUniqueId - ) { - return new Migrations(manifest, migrations as Array>) + static of< + Store, + Vault, + Migrations extends Array>, + >(manifest: SDKManifest, ...migrations: EnsureUniqueId) { + return new Migrations( + manifest, + migrations as Array>, + ) } async init({ effects, previousVersion, }: Parameters[0]) { - const utils = createUtils(effects) + const utils = createUtils(effects) if (!!previousVersion) { const previousVersionEmVer = EmVer.parse(previousVersion) for (const [_, migration] of this.sortedMigrations() @@ -43,7 +46,7 @@ export class Migrations { effects, nextVersion, }: Parameters[0]) { - const utils = createUtils(effects) + const utils = createUtils(effects) if (!!nextVersion) { const nextVersionEmVer = EmVer.parse(nextVersion) const reversed = [...this.sortedMigrations()].reverse() @@ -58,15 +61,16 @@ export class Migrations { export function setupMigrations< Store, - Migrations extends Array>, + Vault, + Migrations extends Array>, >(manifest: SDKManifest, ...migrations: EnsureUniqueId) { - return Migrations.of(manifest, ...migrations) + return Migrations.of(manifest, ...migrations) } // prettier-ignore export type EnsureUniqueId = B extends [] ? A : - B extends [Migration, ...infer Rest] ? ( + B extends [Migration, ...infer Rest] ? ( id extends ids ? "One of the ids are not unique"[] : EnsureUniqueId ) : "There exists a migration that is not a Migration"[] diff --git a/lib/inits/setupInit.ts b/lib/inits/setupInit.ts index fac028f..ad5414b 100644 --- a/lib/inits/setupInit.ts +++ b/lib/inits/setupInit.ts @@ -3,10 +3,10 @@ import { Migrations } from "./migrations/setupMigrations" import { Install } from "./setupInstall" import { Uninstall } from "./setupUninstall" -export function setupInit( - migrations: Migrations, - install: Install, - uninstall: Uninstall, +export function setupInit( + migrations: Migrations, + install: Install, + uninstall: Uninstall, ): { init: ExpectedExports.init uninit: ExpectedExports.uninit diff --git a/lib/inits/setupInstall.ts b/lib/inits/setupInstall.ts index 98e0be5..a24f0e3 100644 --- a/lib/inits/setupInstall.ts +++ b/lib/inits/setupInstall.ts @@ -1,13 +1,13 @@ import { Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util/utils" -export type InstallFn = (opts: { +export type InstallFn = (opts: { effects: Effects - utils: Utils + utils: Utils }) => Promise -export class Install { - private constructor(readonly fn: InstallFn) {} - static of(fn: InstallFn) { +export class Install { + private constructor(readonly fn: InstallFn) {} + static of(fn: InstallFn) { return new Install(fn) } @@ -23,6 +23,6 @@ export class Install { } } -export function setupInstall(fn: InstallFn) { +export function setupInstall(fn: InstallFn) { return Install.of(fn) } diff --git a/lib/inits/setupUninstall.ts b/lib/inits/setupUninstall.ts index 6a76463..209ffd9 100644 --- a/lib/inits/setupUninstall.ts +++ b/lib/inits/setupUninstall.ts @@ -1,13 +1,13 @@ import { Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util/utils" -export type UninstallFn = (opts: { +export type UninstallFn = (opts: { effects: Effects - utils: Utils + utils: Utils }) => Promise -export class Uninstall { - private constructor(readonly fn: UninstallFn) {} - static of(fn: UninstallFn) { +export class Uninstall { + private constructor(readonly fn: UninstallFn) {} + static of(fn: UninstallFn) { return new Uninstall(fn) } @@ -23,6 +23,6 @@ export class Uninstall { } } -export function setupUninstall(fn: UninstallFn) { +export function setupUninstall(fn: UninstallFn) { return Uninstall.of(fn) } diff --git a/lib/mainFn/index.ts b/lib/mainFn/index.ts index 380dc7d..833107e 100644 --- a/lib/mainFn/index.ts +++ b/lib/mainFn/index.ts @@ -23,17 +23,17 @@ import "./Daemons" * @param fn * @returns */ -export const setupMain = ( +export const setupMain = ( fn: (o: { effects: Effects started(onTerm: () => void): null - utils: Utils + utils: Utils }) => Promise>, ): ExpectedExports.main => { return async (options) => { const result = await fn({ ...options, - utils: createMainUtils(options.effects), + utils: createMainUtils(options.effects), }) await result.build().then((x) => x.wait()) } diff --git a/lib/store/getStore.ts b/lib/store/getStore.ts index bff6eec..4ea3a94 100644 --- a/lib/store/getStore.ts +++ b/lib/store/getStore.ts @@ -1,6 +1,4 @@ -import { Parser } from "ts-matches" import { Effects, EnsureStorePath } from "../types" -import { NoAny } from "../util" export class GetStore { constructor( diff --git a/lib/test/output.sdk.ts b/lib/test/output.sdk.ts index a69ccb8..453b896 100644 --- a/lib/test/output.sdk.ts +++ b/lib/test/output.sdk.ts @@ -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) diff --git a/lib/test/store.test.ts b/lib/test/store.test.ts index 5eb43a3..e3d7931 100644 --- a/lib/test/store.test.ts +++ b/lib/test/store.test.ts @@ -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 => { throw new Error("not implemented") } @@ -14,14 +17,14 @@ const noop = () => {} describe("Store", () => { test("types", async () => { ;async () => { - utils(todo()).store.setOwn("/config", { + utils(todo()).store.setOwn("/config", { someValue: "a", }) - utils(todo()).store.setOwn("/config/someValue", "b") - utils(todo()).store.setOwn("", { + utils(todo()).store.setOwn("/config/someValue", "b") + utils(todo()).store.setOwn("", { config: { someValue: "b" }, }) - utils(todo()).store.setOwn( + utils(todo()).store.setOwn( "/config/someValue", // @ts-expect-error Type is wrong for the setting value @@ -33,75 +36,75 @@ describe("Store", () => { "someValue", ) - todo().store.set({ + todo().store.set({ path: "/config/someValue", value: "b", }) - todo().store.set({ + todo().store.set({ //@ts-expect-error Path is wrong path: "/config/someValue", //@ts-expect-error Path is wrong value: "someValueIn", }) - todo().store.set({ + todo().store.set({ //@ts-expect-error Path is wrong path: "/config/some2Value", value: "a", }) - ;(await createMainUtils(todo()) + ;(await createMainUtils(todo()) .store.getOwn("/config/someValue") .const()) satisfies string - ;(await createMainUtils(todo()) + ;(await createMainUtils(todo()) .store.getOwn("/config") - .const()) satisfies WrapperType["config"] + .const()) satisfies Store["config"] await createMainUtils(todo()) // @ts-expect-error Path is wrong .store.getOwn("/config/somdsfeValue") .const() /// ----------------- ERRORS ----------------- - utils(todo()).store.setOwn("", { + utils(todo()).store.setOwn("", { // @ts-expect-error Type is wrong for the setting value config: { someValue: "notInAOrB" }, }) - utils(todo()).store.setOwn( + utils(todo()).store.setOwn( "/config/someValue", // @ts-expect-error Type is wrong for the setting value "notInAOrB", ) - ;(await utils(todo()) + ;(await utils(todo()) .store.getOwn("/config/someValue") // @ts-expect-error Const should normally not be callable .const()) satisfies string - ;(await utils(todo()) + ;(await utils(todo()) .store.getOwn("/config") // @ts-expect-error Const should normally not be callable - .const()) satisfies WrapperType["config"] - await utils(todo()) + .const()) satisfies Store["config"] + await utils(todo()) // @ts-expect-error Path is wrong .store.getOwn("/config/somdsfeValue") // @ts-expect-error Const should normally not be callable .const() /// - ;(await utils(todo()) + ;(await utils(todo()) .store.getOwn("/config/someValue") // @ts-expect-error satisfies type is wrong .const()) satisfies number ;(await createMainUtils(todo()) // @ts-expect-error Path is wrong .store.getOwn("/config/") - .const()) satisfies WrapperType["config"] - ;(await todo().store.get({ + .const()) satisfies Store["config"] + ;(await todo().store.get({ path: "/config/someValue", callback: noop, })) satisfies string - await todo().store.get({ + await todo().store.get({ // @ts-expect-error Path is wrong as in it doesn't match above path: "/config/someV2alue", callback: noop, }) - await todo().store.get({ + await todo().store.get({ // @ts-expect-error Path is wrong as in it doesn't exists in wrapper type path: "/config/someV2alue", callback: noop, diff --git a/lib/types.ts b/lib/types.ts index 2176a88..12be419 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -398,7 +398,7 @@ export type Effects = { vault: { list(): Promise - get(opt: { key: string }): Promise + get(opt: { key: string; callback: () => void }): Promise set(opt: { key: string; value: string }): Promise move(opt: { fromKey: string; toKey: string }): Promise delete(opt: { key: string }): Promise diff --git a/lib/util/index.ts b/lib/util/index.ts index ab8ee08..03dac09 100644 --- a/lib/util/index.ts +++ b/lib/util/index.ts @@ -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 = (effects: T.Effects) => - createUtils(effects) +export const createMainUtils = (effects: T.Effects) => + createUtils(effects) type NeverPossible = { [affine]: string } export type NoAny = NeverPossible extends A diff --git a/lib/util/utils.ts b/lib/util/utils.ts index 7979ce6..5e5e54d 100644 --- a/lib/util/utils.ts +++ b/lib/util/utils.ts @@ -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 = { +export type Utils = { createOrUpdateVault: (opts: { key: string value: string | null | undefined @@ -41,6 +42,10 @@ export type Utils = { value: ExtractStore, ) => Promise } + vault: { + get: (key: keyof Vault & string) => GetVault & WrapperOverWrite + set: (key: keyof Vault & string, value: string) => Promise + } checkPortListening( port: number, options: { @@ -63,9 +68,13 @@ export type Utils = { torHostName: (id: string) => TorHostname nullIfEmpty: typeof nullIfEmpty } -export const utils = ( +export const utils = < + Store = never, + Vault = never, + WrapperOverWrite = { const: never }, +>( effects: T.Effects, -): Utils => ({ +): Utils => ({ createOrUpdateVault: async ({ key, value, @@ -79,7 +88,7 @@ export const utils = ( 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 = ( fileHelper.write(data, effects), nullIfEmpty, store: { - get: ( + get: ( packageId: string, path: T.EnsureStorePath, ) => @@ -112,4 +121,12 @@ export const utils = ( 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(effects, key) as GetVault & WrapperOverWrite, + set: (key: keyof Vault & string, value: string) => + effects.vault.set({ key, value }), + }, }) +function noop(): void {} From 008859a905519ecbbbd20df88ca3a5413e30a3bd Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 16:03:56 -0600 Subject: [PATCH 19/26] feat: Add configRead/save --- lib/StartSdk.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 833d2b3..7486db0 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -239,6 +239,22 @@ export class StartSdk { write, read, ), + setupConfigRead: < + ConfigSpec extends + | Config, any, any> + | Config, never, never>, + >( + _configSpec: ConfigSpec, + fn: Read, + ) => fn, + setupConfigSave: < + ConfigSpec extends + | Config, any, any> + | Config, never, never>, + >( + _configSpec: ConfigSpec, + fn: Save, + ) => fn, setupInit: ( migrations: Migrations, install: Install, From 3b8b23e227969481b1442da53a5adeac53ed3346 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 16:07:31 -0600 Subject: [PATCH 20/26] chore: Update the config builder --- lib/StartSdk.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 7486db0..888e343 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -225,12 +225,11 @@ export class StartSdk { setupBackups(...args), setupConfig: < ConfigType extends - | Record - | Config + | Config | Config, Type extends Record = ExtractConfigType, >( - spec: Config | Config, + spec: ConfigType, write: Save, read: Read, ) => From cc057ea222624ee1206eb60d4e9c93c557b50872 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 16:08:26 -0600 Subject: [PATCH 21/26] chore: Add in the vault --- lib/util/getVault.ts | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 lib/util/getVault.ts diff --git a/lib/util/getVault.ts b/lib/util/getVault.ts new file mode 100644 index 0000000..b88a08d --- /dev/null +++ b/lib/util/getVault.ts @@ -0,0 +1,44 @@ +import { Effects, EnsureStorePath } from "../types" + +export class GetVault { + 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((resolve) => { + callback = resolve + }) + yield await this.effects.vault.get({ + key: this.key, + callback: () => callback(), + }) + await waitForNext + } + } +} +export function getVault(effects: Effects, key: keyof Vault & string) { + return new GetVault(effects, key) +} From 5536dfb55f454953af3ee407acf5befeaa8f1463 Mon Sep 17 00:00:00 2001 From: BluJ Date: Tue, 9 May 2023 16:54:42 -0600 Subject: [PATCH 22/26] chore: update the name of metadata --- lib/StartSdk.ts | 4 ++-- lib/actions/createAction.ts | 10 +++++----- lib/actions/setupActions.ts | 6 +++--- lib/manifest/ManifestTypes.ts | 2 +- lib/types.ts | 8 ++++---- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 888e343..659983c 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -13,7 +13,7 @@ import { import { Variants } from "./config/builder/variants" import { CreatedAction, createAction } from "./actions/createAction" import { - ActionMetaData, + ActionMetadata, Effects, ActionResult, Metadata, @@ -106,7 +106,7 @@ export class StartSdk { | Config, Type extends Record = ExtractConfigType, >( - metaData: Omit & { + metaData: Omit & { input: Config | Config }, fn: (options: { diff --git a/lib/actions/createAction.ts b/lib/actions/createAction.ts index 7a9a7c5..7e0979c 100644 --- a/lib/actions/createAction.ts +++ b/lib/actions/createAction.ts @@ -1,5 +1,5 @@ import { Config, ExtractConfigType } from "../config/builder/config" -import { ActionMetaData, ActionResult, Effects, ExportedAction } from "../types" +import { ActionMetadata, ActionResult, Effects, ExportedAction } from "../types" import { createUtils } from "../util" import { Utils, utils } from "../util/utils" @@ -13,7 +13,7 @@ export class CreatedAction< Type extends Record = ExtractConfigType, > { private constructor( - public readonly myMetaData: Omit, + public readonly myMetaData: Omit, readonly fn: (options: { effects: Effects utils: Utils @@ -32,7 +32,7 @@ export class CreatedAction< | Config, Type extends Record = ExtractConfigType, >( - metaData: Omit & { + metaData: Omit & { input: Config | Config }, fn: (options: { @@ -65,10 +65,10 @@ export class CreatedAction< }) } - async actionMetaData(options: { + async ActionMetadata(options: { effects: Effects utils: Utils - }): Promise { + }): Promise { return { ...this.myMetaData, input: await this.input.build(options), diff --git a/lib/actions/setupActions.ts b/lib/actions/setupActions.ts index f2230ed..4f3264d 100644 --- a/lib/actions/setupActions.ts +++ b/lib/actions/setupActions.ts @@ -17,14 +17,14 @@ export function setupActions( get actions() { return myActions() }, - async actionsMetaData({ effects }: { effects: Effects }) { + async actionsMetadata({ effects }: { effects: Effects }) { const utils = createUtils(effects) return Promise.all( - createdActions.map((x) => x.actionMetaData({ effects, utils })), + createdActions.map((x) => x.ActionMetadata({ effects, utils })), ) }, } satisfies { actions: ExpectedExports.actions - actionsMetaData: ExpectedExports.actionsMetaData + actionsMetadata: ExpectedExports.actionsMetadata } } diff --git a/lib/manifest/ManifestTypes.ts b/lib/manifest/ManifestTypes.ts index 80b91ad..65c36d9 100644 --- a/lib/manifest/ManifestTypes.ts +++ b/lib/manifest/ManifestTypes.ts @@ -1,5 +1,5 @@ import { ValidEmVer } from "../emverLite/mod" -import { ActionMetaData } from "../types" +import { ActionMetadata } from "../types" export interface Container { /** This should be pointing to a docker container name */ diff --git a/lib/types.ts b/lib/types.ts index 12be419..907c308 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -45,9 +45,9 @@ export namespace ExpectedExports { } } - export type actionsMetaData = (options: { + export type actionsMetadata = (options: { effects: Effects - }) => Promise> + }) => Promise> /** * This is the entrypoint for the main container. Used to start up something like the service that the @@ -154,7 +154,7 @@ export type DaemonReturned = { term(): Promise } -export type ActionMetaData = { +export type ActionMetadata = { name: string description: string id: string @@ -320,7 +320,7 @@ export type Effects = { * * @param options */ - exportAction(options: ActionMetaData): Promise + exportAction(options: ActionMetadata): Promise /** * Remove an action that was exported. Used problably during main or during setConfig. */ From 33da2322b04e696e911c4b44f69c59c68701dc4c Mon Sep 17 00:00:00 2001 From: BluJ Date: Wed, 10 May 2023 15:47:28 -0600 Subject: [PATCH 23/26] feat: Dependencies --- lib/StartSdk.ts | 2 + lib/dependency/mountDependencies.ts | 43 ++++++++ lib/dependency/setupDependencyMounts.ts | 70 ++++++++++++ lib/manifest/ManifestTypes.ts | 62 ++++++----- lib/test/mountDependencies.test.ts | 139 ++++++++++++++++++++++++ lib/types.ts | 5 +- lib/util/utils.ts | 33 ++++++ package-lock.json | 10 +- package.json | 1 + 9 files changed, 329 insertions(+), 36 deletions(-) create mode 100644 lib/dependency/mountDependencies.ts create mode 100644 lib/dependency/setupDependencyMounts.ts create mode 100644 lib/test/mountDependencies.test.ts diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 659983c..40cbb70 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -47,6 +47,7 @@ import { setupMain } from "./mainFn" import { defaultTrigger } from "./trigger/defaultTrigger" import { changeOnFirstSuccess, cooldownTrigger } from "./trigger" import setupConfig, { Read, Save } from "./config/setupConfig" +import { setupDependencyMounts } from "./dependency/setupDependencyMounts" // prettier-ignore type AnyNeverCond = @@ -254,6 +255,7 @@ export class StartSdk { _configSpec: ConfigSpec, fn: Save, ) => fn, + setupDependencyMounts, setupInit: ( migrations: Migrations, install: Install, diff --git a/lib/dependency/mountDependencies.ts b/lib/dependency/mountDependencies.ts new file mode 100644 index 0000000..4721d26 --- /dev/null +++ b/lib/dependency/mountDependencies.ts @@ -0,0 +1,43 @@ +import { Effects } from "../types" +import { + Path, + ManifestId, + VolumeName, + NamedPath, + matchPath, +} from "./setupDependencyMounts" + +export type MountDependenciesOut = + // prettier-ignore + A extends Path ? string : A extends Record ? { + [P in keyof A]: MountDependenciesOut; + } : never +export async function mountDependencies< + In extends + | Record>> + | Record> + | Record + | Path, +>(effects: Effects, value: In): Promise> { + if (matchPath.test(value)) { + const mountPath = `${value.manifest.id}/${value.volume}/${value.name}` + + return (await effects.mount({ + location: { + path: mountPath, + }, + target: { + packageId: value.manifest.id, + path: value.path, + readonly: value.readonly, + volumeId: value.volume, + }, + })) as MountDependenciesOut + } + return Object.fromEntries( + Object.entries(value).map(([key, value]) => [ + key, + mountDependencies(effects, value), + ]), + ) as Record as MountDependenciesOut +} diff --git a/lib/dependency/setupDependencyMounts.ts b/lib/dependency/setupDependencyMounts.ts new file mode 100644 index 0000000..e3c8cdd --- /dev/null +++ b/lib/dependency/setupDependencyMounts.ts @@ -0,0 +1,70 @@ +import { boolean, object, string } from "ts-matches" +import { SDKManifest } from "../manifest/ManifestTypes" +import { deepMerge } from "../util/deepMerge" + +export type VolumeName = string +export type NamedPath = string +export type ManifestId = string + +export const matchPath = object({ + name: string, + volume: string, + path: string, + manifest: object({ + id: string, + }), + readonly: boolean, +}) +export type Path = typeof matchPath._TYPE +export type BuildPath = { + [PId in M["manifest"]["id"]]: { + [V in M["volume"]]: { + [N in M["name"]]: M + } + } +} +type ValidIfNotInNested< + Building, + M extends Path, +> = Building extends BuildPath ? never : M +class SetupDependencyMounts { + private constructor(readonly building: Building) {} + + static of() { + return new SetupDependencyMounts({}) + } + + addPath< + NamedPath extends string, + VolumeName extends string, + PathNamed extends string, + M extends SDKManifest, + >( + newPath: ValidIfNotInNested< + Building, + { + name: NamedPath + volume: VolumeName + path: PathNamed + manifest: M + readonly: boolean + } + >, + ) { + const building = deepMerge(this.building, { + [newPath.manifest.id]: { + [newPath.volume]: { + [newPath.name]: newPath, + }, + }, + }) as Building & BuildPath + return new SetupDependencyMounts(building) + } + build() { + return this.building + } +} + +export function setupDependencyMounts() { + return SetupDependencyMounts.of() +} diff --git a/lib/manifest/ManifestTypes.ts b/lib/manifest/ManifestTypes.ts index 65c36d9..50c97c2 100644 --- a/lib/manifest/ManifestTypes.ts +++ b/lib/manifest/ManifestTypes.ts @@ -14,64 +14,68 @@ export interface Container { export type ManifestVersion = ValidEmVer -export interface SDKManifest { +export type SDKManifest = { /** The package identifier used by the OS. This must be unique amongst all other known packages */ - id: string + readonly id: string /** A human readable service title */ - title: string + readonly title: string /** Service version - accepts up to four digits, where the last confirms to revisions necessary for StartOs * - see documentation: https://github.com/Start9Labs/emver-rs. This value will change with each release of * the service */ - version: ManifestVersion + readonly version: ManifestVersion /** Release notes for the update - can be a string, paragraph or URL */ - releaseNotes: string + readonly releaseNotes: string /** The type of license for the project. Include the LICENSE in the root of the project directory. A license is required for a Start9 package.*/ - license: string // name of license + readonly license: string // name of license /** A list of normie (hosted, SaaS, custodial, etc) services this services intends to replace */ - replaces: string[] + readonly replaces: Readonly /** The Start9 wrapper repository URL for the package. This repo contains the manifest file (this), * any scripts necessary for configuration, backups, actions, or health checks (more below). This key * must exist. But could be embedded into the source repository */ - wrapperRepo: string + readonly wrapperRepo: string /** The original project repository URL. There is no upstream repo in this example */ - upstreamRepo: string + readonly upstreamRepo: string /** URL to the support site / channel for the project. This key can be omitted if none exists, or it can link to the original project repository issues */ - supportSite: string + readonly supportSite: string /** URL to the marketing site for the project. If there is no marketing site, it can link to the original project repository */ - marketingSite: string + readonly marketingSite: string /** URL where users can donate to the upstream project */ - donationUrl: string | null + readonly donationUrl: string | null /**Human readable descriptions for the service. These are used throughout the StartOS user interface, primarily in the marketplace. */ - description: { + readonly description: { /**This is the first description visible to the user in the marketplace */ - short: string + readonly short: string /** This description will display with additional details in the service's individual marketplace page */ - long: string + readonly long: string } /** These assets are static files necessary for packaging the service for Start9 (into an s9pk). * Each value is a path to the specified asset. If an asset is missing from this list, or otherwise * denoted, it will be defaulted to the values denoted below. */ - assets: { - icon: string // file path - instructions: string // file path - license: string // file path + readonly assets: { + /** This is the file path for the icon that will be this packages icon on the ui */ + readonly icon: string + /** Instructions path to be seen in the ui section of the package */ + readonly instructions: string + /** license path */ + readonly license: string } /** Defines the containers needed to run the main and mounted volumes */ - containers: Record + readonly containers: Record /** This denotes any data, asset, or pointer volumes that should be connected when the "docker run" command is invoked */ - volumes: Record - alerts: { - install: string | null - update: string | null - uninstall: string | null - restore: string | null - start: string | null - stop: string | null + readonly volumes: Record + + readonly alerts: { + readonly install: string | null + readonly update: string | null + readonly uninstall: string | null + readonly restore: string | null + readonly start: string | null + readonly stop: string | null } - dependencies: Record + readonly dependencies: Readonly> } export interface ManifestDependency { diff --git a/lib/test/mountDependencies.test.ts b/lib/test/mountDependencies.test.ts new file mode 100644 index 0000000..c6b9e01 --- /dev/null +++ b/lib/test/mountDependencies.test.ts @@ -0,0 +1,139 @@ +import { setupManifest } from "../manifest/setupManifest" +import { mountDependencies } from "../dependency/mountDependencies" +import { + BuildPath, + setupDependencyMounts, +} from "../dependency/setupDependencyMounts" + +describe("mountDependencies", () => { + const clnManifest = setupManifest({ + id: "cln", + title: "", + version: "1", + releaseNotes: "", + license: "", + replaces: [], + wrapperRepo: "", + upstreamRepo: "", + supportSite: "", + marketingSite: "", + donationUrl: null, + description: { + short: "", + long: "", + }, + assets: { + icon: "", + instructions: "", + license: "", + }, + containers: {}, + volumes: { main: "data" }, + alerts: { + install: null, + update: null, + uninstall: null, + restore: null, + start: null, + stop: null, + }, + dependencies: {}, + }) + const lndManifest = setupManifest({ + id: "lnd", + title: "", + version: "1", + releaseNotes: "", + license: "", + replaces: [], + wrapperRepo: "", + upstreamRepo: "", + supportSite: "", + marketingSite: "", + donationUrl: null, + description: { + short: "", + long: "", + }, + assets: { + icon: "", + instructions: "", + license: "", + }, + containers: {}, + volumes: {}, + alerts: { + install: null, + update: null, + uninstall: null, + restore: null, + start: null, + stop: null, + }, + dependencies: {}, + }) + clnManifest.id + type test = BuildPath<{ + name: "root" + manifest: typeof clnManifest + volume: "main" + path: "/" + readonly: true + }> extends BuildPath<{ + name: "root" + manifest: typeof clnManifest + volume: "main2" + path: "/" + readonly: true + }> + ? true + : false + + test("Types work", () => { + const dependencyMounts = setupDependencyMounts() + .addPath({ + name: "root", + volume: "main", + path: "/", + manifest: clnManifest, + readonly: true, + }) + .addPath({ + name: "root", + manifest: lndManifest, + volume: "main", + path: "/", + readonly: true, + }) + .build() + ;() => { + const test = mountDependencies( + null as any, + dependencyMounts, + ) satisfies Promise<{ + cln: { + main: { + root: string + } + } + lnd: { + main: { + root: string + } + } + }> + const test2 = mountDependencies( + null as any, + dependencyMounts.cln, + ) satisfies Promise<{ + main: { root: string } + }> + const test3 = mountDependencies( + null as any, + dependencyMounts.cln.main, + ) satisfies Promise<{ + root: string + }> + } + }) +}) diff --git a/lib/types.ts b/lib/types.ts index 907c308..28feb6e 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -383,7 +383,8 @@ export type Effects = { mount(options: { location: { - volumeId: string + /** If there is no volumeId then we mount to runMedia a special mounting location */ + volumeId?: string path: string } target: { @@ -392,7 +393,7 @@ export type Effects = { path: string readonly: boolean } - }): Promise + }): Promise stopped(packageId?: string): Promise diff --git a/lib/util/utils.ts b/lib/util/utils.ts index 5e5e54d..95cd1f0 100644 --- a/lib/util/utils.ts +++ b/lib/util/utils.ts @@ -16,7 +16,22 @@ import { DefaultString } from "../config/configTypes" import { getDefaultString } from "./getDefaultString" import { GetStore, getStore } from "../store/getStore" import { GetVault, getVault } from "./getVault" +import { + MountDependenciesOut, + mountDependencies, +} from "../dependency/mountDependencies" +import { + ManifestId, + VolumeName, + NamedPath, + Path, +} from "../dependency/setupDependencyMounts" +// prettier-ignore +type skipFirstParam = + A extends [any, ...infer B] ? B : + A extends [] ? [] : + never export type Utils = { createOrUpdateVault: (opts: { key: string @@ -67,6 +82,15 @@ export type Utils = { networkBuilder: () => NetworkBuilder torHostName: (id: string) => TorHostname nullIfEmpty: typeof nullIfEmpty + mountDependencies: < + In extends + | Record>> + | Record> + | Record + | Path, + >( + value: In, + ) => Promise> } export const utils = < Store = never, @@ -128,5 +152,14 @@ export const utils = < set: (key: keyof Vault & string, value: string) => effects.vault.set({ key, value }), }, + mountDependencies: < + In extends + | Record>> + | Record> + | Record + | Path, + >( + value: In, + ) => mountDependencies(effects, value), }) function noop(): void {} diff --git a/package-lock.json b/package-lock.json index e2b1626..3575f69 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "ts-node": "^10.9.1", "tsc-multi": "^0.6.1", "tsconfig-paths": "^3.14.2", + "typescript": "^5.0.0", "vitest": "^0.29.2" } }, @@ -4878,17 +4879,16 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.4.tgz", + "integrity": "sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==", "dev": true, - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=12.20" } }, "node_modules/ufo": { diff --git a/package.json b/package.json index c25cd26..c3d8b66 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "ts-node": "^10.9.1", "tsc-multi": "^0.6.1", "tsconfig-paths": "^3.14.2", + "typescript": "^5.0.4", "vitest": "^0.29.2" }, "declaration": true From cdf42ca3b66bcfa5a44fd3850ee2df8363df88ba Mon Sep 17 00:00:00 2001 From: BluJ Date: Wed, 10 May 2023 16:30:42 -0600 Subject: [PATCH 24/26] feat: Making the auto config --- lib/StartSdk.ts | 52 +++++++++++++++++++++---------- lib/autoconfig/AutoConfig.ts | 42 ++++++++----------------- lib/autoconfig/setupAutoConfig.ts | 24 +++++--------- lib/test/output.sdk.ts | 43 ++++++++++++++++++++++++- lib/test/setupAutoConfig.test.ts | 27 ++++++++++++++++ lib/util/utils.ts | 5 --- package-lock.json | 2 +- 7 files changed, 126 insertions(+), 69 deletions(-) create mode 100644 lib/test/setupAutoConfig.test.ts diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 40cbb70..388d93b 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -18,9 +18,10 @@ import { ActionResult, Metadata, BackupOptions, + DeepPartial, } from "./types" import { Utils } from "./util/utils" -import { AutoConfig, AutoConfigFrom } from "./autoconfig/AutoConfig" +import { AutoConfig } from "./autoconfig/AutoConfig" import { BackupSet, Backups } from "./backup/Backups" import { smtpConfig } from "./config/configConstants" import { Daemons } from "./mainFn/Daemons" @@ -75,10 +76,29 @@ export class StartSdk { isReady: AnyNeverCond<[Manifest, Store, Vault], "Build not ready", true>, ) { return { - AutoConfig: >( - configs: AutoConfigFrom, - path: keyof AutoConfigFrom, - ) => new AutoConfig(configs, path), + AutoConfig: { + of< + LocalConfig extends Record, + RemoteConfig extends Record, + >({ + localConfig, + remoteConfig, + autoconfig, + }: { + localConfig: Config + remoteConfig: Config + autoconfig: (options: { + effects: Effects + localConfig: LocalConfig + remoteConfig: RemoteConfig + utils: Utils + }) => Promise> + }) { + return new AutoConfig( + autoconfig, + ) + }, + }, Backups: { volumes: (...volumeNames: Array) => Backups.volumes(...volumeNames), @@ -209,19 +229,17 @@ export class StartSdk { }, setupActions: (...createdActions: CreatedAction[]) => setupActions(...createdActions), - setupAutoConfig: < - Input extends Record, - NestedConfigs extends { - [key in keyof Manifest["dependencies"]]: unknown - }, - >( + setupAutoConfig: >( config: Config, - autoConfigs: AutoConfigFrom, - ) => - setupAutoConfig( - config, - autoConfigs, - ), + autoConfigs: { + [K in keyof Manifest["dependencies"]]: AutoConfig< + Store, + Vault, + Input, + any + > + }, + ) => setupAutoConfig(config, autoConfigs), setupBackups: (...args: SetupBackupsParams) => setupBackups(...args), setupConfig: < diff --git a/lib/autoconfig/AutoConfig.ts b/lib/autoconfig/AutoConfig.ts index 484f3bb..ba4c25a 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/autoconfig/AutoConfig.ts @@ -4,31 +4,19 @@ import { deepEqual } from "../util/deepEqual" import { deepMerge } from "../util/deepMerge" import { Config } from "../config/builder/config" -export type AutoConfigFrom< - Store, - Vault, - Input, - NestedConfigs extends Record, -> = { - [key in keyof NestedConfigs & string]: { - serviceConfig: Config - autoConfig: (options: { - effects: Effects - localConfig: Input - remoteConfig: NestedConfigs[key] - utils: Utils - }) => Promise> - } -} export class AutoConfig< Store, Vault, - Input, - NestedConfigs extends Record, + Input extends Record, + RemoteConfig extends Record, > { constructor( - readonly configs: AutoConfigFrom, - readonly path: keyof AutoConfigFrom, + readonly autoconfig: (options: { + effects: Effects + localConfig: Input + remoteConfig: RemoteConfig + utils: Utils + }) => Promise>, ) {} async check( @@ -39,19 +27,15 @@ export class AutoConfig< ...options, utils: utils(options.effects), localConfig: options.localConfig as Input, - remoteConfig: options.remoteConfig as any, + remoteConfig: options.remoteConfig as RemoteConfig, } if ( !deepEqual( origConfig, - deepMerge( - {}, - options.localConfig, - await this.configs[this.path].autoConfig(newOptions), - ), + deepMerge({}, options.localConfig, await this.autoconfig(newOptions)), ) ) - throw new Error(`Check failed for ${this.path}`) + throw new Error(`Check failed`) } async autoConfigure( options: Parameters[0], @@ -64,8 +48,8 @@ export class AutoConfig< } return deepMerge( {}, - options.localConfig, - await this.configs[this.path].autoConfig(newOptions), + options.remoteConfig, + await this.autoconfig(newOptions), ) } } diff --git a/lib/autoconfig/setupAutoConfig.ts b/lib/autoconfig/setupAutoConfig.ts index 6055929..00ed044 100644 --- a/lib/autoconfig/setupAutoConfig.ts +++ b/lib/autoconfig/setupAutoConfig.ts @@ -1,30 +1,22 @@ import { Config } from "../config/builder/config" import { SDKManifest } from "../manifest/ManifestTypes" -import { AutoConfig, AutoConfigFrom } from "./AutoConfig" +import { AutoConfig } from "./AutoConfig" export function setupAutoConfig< Store, Vault, Input extends Record, Manifest extends SDKManifest, - NestedConfigs extends { - [key in keyof Manifest["dependencies"]]: unknown - }, >( _config: Config, - autoConfigs: AutoConfigFrom, -) { - type C = typeof autoConfigs - const answer = { ...autoConfigs } as unknown as { - [k in keyof C]: AutoConfig - } - for (const key in autoConfigs) { - answer[key as keyof typeof autoConfigs] = new AutoConfig< + autoConfigs: { + [key in keyof Manifest["dependencies"] & string]: AutoConfig< Store, Vault, Input, - NestedConfigs - >(autoConfigs, key as keyof typeof autoConfigs) - } - return answer + any + > + }, +) { + return autoConfigs } diff --git a/lib/test/output.sdk.ts b/lib/test/output.sdk.ts index 453b896..4802317 100644 --- a/lib/test/output.sdk.ts +++ b/lib/test/output.sdk.ts @@ -1,8 +1,49 @@ import { StartSdk } from "../StartSdk" +import { setupManifest } from "../manifest/setupManifest" export type Manifest = any export const sdk = StartSdk.of() - .withManifest({} as any) + .withManifest( + setupManifest({ + id: "testOutput", + title: "", + version: "1.0", + releaseNotes: "", + license: "", + replaces: [], + wrapperRepo: "", + upstreamRepo: "", + supportSite: "", + marketingSite: "", + donationUrl: null, + description: { + short: "", + long: "", + }, + assets: { + icon: "", + instructions: "", + license: "", + }, + containers: {}, + volumes: {}, + alerts: { + install: null, + update: null, + uninstall: null, + restore: null, + start: null, + stop: null, + }, + dependencies: { + remoteTest: { + description: "", + requirement: { how: "", type: "opt-in" }, + version: "1.0", + }, + }, + }), + ) .withStore<{ storeRoot: { storeLeaf: "value" } }>() .withVault<{ vaultRoot: "value" }>() .build(true) diff --git a/lib/test/setupAutoConfig.test.ts b/lib/test/setupAutoConfig.test.ts new file mode 100644 index 0000000..8af417d --- /dev/null +++ b/lib/test/setupAutoConfig.test.ts @@ -0,0 +1,27 @@ +import { sdk } from "./output.sdk" + +describe("setupAutoConfig", () => { + test("test", () => { + const testConfig = sdk.Config.of({ + test: sdk.Value.text({ + name: "testValue", + required: false, + }), + }) + + const testConfig2 = sdk.Config.of({ + test2: sdk.Value.text({ + name: "testValue2", + required: false, + }), + }) + const remoteTest = sdk.AutoConfig.of({ + localConfig: testConfig, + remoteConfig: testConfig2, + autoconfig: async ({}) => {}, + }) + sdk.setupAutoConfig(testConfig, { + remoteTest, + }) + }) +}) diff --git a/lib/util/utils.ts b/lib/util/utils.ts index 95cd1f0..696a80c 100644 --- a/lib/util/utils.ts +++ b/lib/util/utils.ts @@ -27,11 +27,6 @@ import { Path, } from "../dependency/setupDependencyMounts" -// prettier-ignore -type skipFirstParam = - A extends [any, ...infer B] ? B : - A extends [] ? [] : - never export type Utils = { createOrUpdateVault: (opts: { key: string diff --git a/package-lock.json b/package-lock.json index 3575f69..2788e93 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,7 +20,7 @@ "ts-node": "^10.9.1", "tsc-multi": "^0.6.1", "tsconfig-paths": "^3.14.2", - "typescript": "^5.0.0", + "typescript": "^5.0.4", "vitest": "^0.29.2" } }, From 9521865c596f3fa7c2c39d0a6fcbced2341f0f60 Mon Sep 17 00:00:00 2001 From: BluJ Date: Wed, 10 May 2023 16:49:10 -0600 Subject: [PATCH 25/26] chore: Update to the new dependencyConfig --- lib/StartSdk.ts | 239 +++++++++--------- .../DependencyConfig.ts} | 13 +- lib/{autoconfig => dependencyConfig}/index.ts | 4 +- .../setupDependencyConfig.ts} | 6 +- lib/index.ts | 2 +- ....test.ts => setupDependencyConfig.test.ts} | 8 +- 6 files changed, 140 insertions(+), 132 deletions(-) rename lib/{autoconfig/AutoConfig.ts => dependencyConfig/DependencyConfig.ts} (85%) rename lib/{autoconfig => dependencyConfig}/index.ts (78%) rename lib/{autoconfig/setupAutoConfig.ts => dependencyConfig/setupDependencyConfig.ts} (67%) rename lib/test/{setupAutoConfig.test.ts => setupDependencyConfig.test.ts} (71%) diff --git a/lib/StartSdk.ts b/lib/StartSdk.ts index 388d93b..b0365d3 100644 --- a/lib/StartSdk.ts +++ b/lib/StartSdk.ts @@ -21,7 +21,7 @@ import { DeepPartial, } from "./types" import { Utils } from "./util/utils" -import { AutoConfig } from "./autoconfig/AutoConfig" +import { DependencyConfig } from "./dependencyConfig/DependencyConfig" import { BackupSet, Backups } from "./backup/Backups" import { smtpConfig } from "./config/configConstants" import { Daemons } from "./mainFn/Daemons" @@ -35,7 +35,7 @@ import { List } from "./config/builder/list" import { Migration } from "./inits/migrations/Migration" import { Install, InstallFn, setupInstall } from "./inits/setupInstall" import { setupActions } from "./actions/setupActions" -import { setupAutoConfig } from "./autoconfig/setupAutoConfig" +import { setupDependencyConfig } from "./dependencyConfig/setupDependencyConfig" import { SetupBackupsParams, setupBackups } from "./backup/setupBackups" import { setupInit } from "./inits/setupInit" import { @@ -76,29 +76,106 @@ export class StartSdk { isReady: AnyNeverCond<[Manifest, Store, Vault], "Build not ready", true>, ) { return { - AutoConfig: { - of< - LocalConfig extends Record, - RemoteConfig extends Record, - >({ - localConfig, - remoteConfig, - autoconfig, - }: { - localConfig: Config - remoteConfig: Config - autoconfig: (options: { - effects: Effects - localConfig: LocalConfig - remoteConfig: RemoteConfig - utils: Utils - }) => Promise> - }) { - return new AutoConfig( - autoconfig, - ) + configConstants: { smtpConfig }, + createAction: < + Store, + ConfigType extends + | Record + | Config + | Config, + Type extends Record = ExtractConfigType, + >( + metaData: Omit & { + input: Config | Config }, + fn: (options: { + effects: Effects + utils: Utils + input: Type + }) => Promise, + ) => createAction(metaData, fn), + healthCheck: { + checkPortListening, + checkWebUrl, + of: healthCheck, + runHealthScript, }, + setupActions: (...createdActions: CreatedAction[]) => + setupActions(...createdActions), + setupBackups: (...args: SetupBackupsParams) => + setupBackups(...args), + setupConfig: < + ConfigType extends + | Config + | Config, + Type extends Record = ExtractConfigType, + >( + spec: ConfigType, + write: Save, + read: Read, + ) => + setupConfig( + spec, + write, + read, + ), + setupConfigRead: < + ConfigSpec extends + | Config, any, any> + | Config, never, never>, + >( + _configSpec: ConfigSpec, + fn: Read, + ) => fn, + setupConfigSave: < + ConfigSpec extends + | Config, any, any> + | Config, never, never>, + >( + _configSpec: ConfigSpec, + fn: Save, + ) => fn, + setupDependencyConfig: >( + config: Config, + autoConfigs: { + [K in keyof Manifest["dependencies"]]: DependencyConfig< + Store, + Vault, + Input, + any + > + }, + ) => + setupDependencyConfig( + config, + autoConfigs, + ), + setupDependencyMounts, + setupInit: ( + migrations: Migrations, + install: Install, + uninstall: Uninstall, + ) => setupInit(migrations, install, uninstall), + setupInstall: (fn: InstallFn) => Install.of(fn), + setupMain: ( + fn: (o: { + effects: Effects + started(onTerm: () => void): null + utils: Utils + }) => Promise>, + ) => setupMain(fn), + setupMigrations: >>( + ...migrations: EnsureUniqueId + ) => + setupMigrations(this.manifest, ...migrations), + setupUninstall: (fn: UninstallFn) => + setupUninstall(fn), + trigger: { + defaultTrigger, + cooldownTrigger, + changeOnFirstSuccess, + }, + Backups: { volumes: (...volumeNames: Array) => Backups.volumes(...volumeNames), @@ -118,30 +195,29 @@ export class StartSdk { spec: Spec, ) => Config.of(spec), }, - configConstants: { smtpConfig }, - createAction: < - Store, - ConfigType extends - | Record - | Config - | Config, - Type extends Record = ExtractConfigType, - >( - metaData: Omit & { - input: Config | Config - }, - fn: (options: { - effects: Effects - utils: Utils - input: Type - }) => Promise, - ) => createAction(metaData, fn), Daemons: { of: Daemons.of }, - healthCheck: { - checkPortListening, - checkWebUrl, - of: healthCheck, - runHealthScript, + DependencyConfig: { + of< + LocalConfig extends Record, + RemoteConfig extends Record, + >({ + localConfig, + remoteConfig, + dependencyConfig, + }: { + localConfig: Config + remoteConfig: Config + dependencyConfig: (options: { + effects: Effects + localConfig: LocalConfig + remoteConfig: RemoteConfig + utils: Utils + }) => Promise> + }) { + return new DependencyConfig( + dependencyConfig, + ) + }, }, List: { text: List.text, @@ -227,77 +303,6 @@ export class StartSdk { }) => Promise }) => Migration.of(options), }, - setupActions: (...createdActions: CreatedAction[]) => - setupActions(...createdActions), - setupAutoConfig: >( - config: Config, - autoConfigs: { - [K in keyof Manifest["dependencies"]]: AutoConfig< - Store, - Vault, - Input, - any - > - }, - ) => setupAutoConfig(config, autoConfigs), - setupBackups: (...args: SetupBackupsParams) => - setupBackups(...args), - setupConfig: < - ConfigType extends - | Config - | Config, - Type extends Record = ExtractConfigType, - >( - spec: ConfigType, - write: Save, - read: Read, - ) => - setupConfig( - spec, - write, - read, - ), - setupConfigRead: < - ConfigSpec extends - | Config, any, any> - | Config, never, never>, - >( - _configSpec: ConfigSpec, - fn: Read, - ) => fn, - setupConfigSave: < - ConfigSpec extends - | Config, any, any> - | Config, never, never>, - >( - _configSpec: ConfigSpec, - fn: Save, - ) => fn, - setupDependencyMounts, - setupInit: ( - migrations: Migrations, - install: Install, - uninstall: Uninstall, - ) => setupInit(migrations, install, uninstall), - setupInstall: (fn: InstallFn) => Install.of(fn), - setupMain: ( - fn: (o: { - effects: Effects - started(onTerm: () => void): null - utils: Utils - }) => Promise>, - ) => setupMain(fn), - setupMigrations: >>( - ...migrations: EnsureUniqueId - ) => - setupMigrations(this.manifest, ...migrations), - setupUninstall: (fn: UninstallFn) => - setupUninstall(fn), - trigger: { - defaultTrigger, - cooldownTrigger, - changeOnFirstSuccess, - }, Value: { toggle: Value.toggle, text: Value.text, diff --git a/lib/autoconfig/AutoConfig.ts b/lib/dependencyConfig/DependencyConfig.ts similarity index 85% rename from lib/autoconfig/AutoConfig.ts rename to lib/dependencyConfig/DependencyConfig.ts index ba4c25a..9f01f77 100644 --- a/lib/autoconfig/AutoConfig.ts +++ b/lib/dependencyConfig/DependencyConfig.ts @@ -2,16 +2,15 @@ import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types" import { Utils, utils } from "../util/utils" import { deepEqual } from "../util/deepEqual" import { deepMerge } from "../util/deepMerge" -import { Config } from "../config/builder/config" -export class AutoConfig< +export class DependencyConfig< Store, Vault, Input extends Record, RemoteConfig extends Record, > { constructor( - readonly autoconfig: (options: { + readonly dependencyConfig: (options: { effects: Effects localConfig: Input remoteConfig: RemoteConfig @@ -32,7 +31,11 @@ export class AutoConfig< if ( !deepEqual( origConfig, - deepMerge({}, options.localConfig, await this.autoconfig(newOptions)), + deepMerge( + {}, + options.localConfig, + await this.dependencyConfig(newOptions), + ), ) ) throw new Error(`Check failed`) @@ -49,7 +52,7 @@ export class AutoConfig< return deepMerge( {}, options.remoteConfig, - await this.autoconfig(newOptions), + await this.dependencyConfig(newOptions), ) } } diff --git a/lib/autoconfig/index.ts b/lib/dependencyConfig/index.ts similarity index 78% rename from lib/autoconfig/index.ts rename to lib/dependencyConfig/index.ts index 031733b..3fe78b4 100644 --- a/lib/autoconfig/index.ts +++ b/lib/dependencyConfig/index.ts @@ -5,5 +5,5 @@ export type ReadonlyDeep = export type MaybePromise = Promise | A export type Message = string -import "./AutoConfig" -import "./setupAutoConfig" +import "./DependencyConfig" +import "./setupDependencyConfig" diff --git a/lib/autoconfig/setupAutoConfig.ts b/lib/dependencyConfig/setupDependencyConfig.ts similarity index 67% rename from lib/autoconfig/setupAutoConfig.ts rename to lib/dependencyConfig/setupDependencyConfig.ts index 00ed044..475015b 100644 --- a/lib/autoconfig/setupAutoConfig.ts +++ b/lib/dependencyConfig/setupDependencyConfig.ts @@ -1,8 +1,8 @@ import { Config } from "../config/builder/config" import { SDKManifest } from "../manifest/ManifestTypes" -import { AutoConfig } from "./AutoConfig" +import { DependencyConfig } from "./DependencyConfig" -export function setupAutoConfig< +export function setupDependencyConfig< Store, Vault, Input extends Record, @@ -10,7 +10,7 @@ export function setupAutoConfig< >( _config: Config, autoConfigs: { - [key in keyof Manifest["dependencies"] & string]: AutoConfig< + [key in keyof Manifest["dependencies"] & string]: DependencyConfig< Store, Vault, Input, diff --git a/lib/index.ts b/lib/index.ts index 85c32e1..f8a076a 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -11,7 +11,7 @@ import "@iarna/toml" import "./types" import "./util" import "yaml" -import "./autoconfig" +import "./dependencyConfig" import "./actions" import "./manifest" import "./inits" diff --git a/lib/test/setupAutoConfig.test.ts b/lib/test/setupDependencyConfig.test.ts similarity index 71% rename from lib/test/setupAutoConfig.test.ts rename to lib/test/setupDependencyConfig.test.ts index 8af417d..4fac5d0 100644 --- a/lib/test/setupAutoConfig.test.ts +++ b/lib/test/setupDependencyConfig.test.ts @@ -1,6 +1,6 @@ import { sdk } from "./output.sdk" -describe("setupAutoConfig", () => { +describe("setupDependencyConfig", () => { test("test", () => { const testConfig = sdk.Config.of({ test: sdk.Value.text({ @@ -15,12 +15,12 @@ describe("setupAutoConfig", () => { required: false, }), }) - const remoteTest = sdk.AutoConfig.of({ + const remoteTest = sdk.DependencyConfig.of({ localConfig: testConfig, remoteConfig: testConfig2, - autoconfig: async ({}) => {}, + dependencyConfig: async ({}) => {}, }) - sdk.setupAutoConfig(testConfig, { + sdk.setupDependencyConfig(testConfig, { remoteTest, }) }) From a76344d95f0bce20e87a77f7c814c394c1e41a78 Mon Sep 17 00:00:00 2001 From: BluJ Date: Wed, 10 May 2023 16:52:44 -0600 Subject: [PATCH 26/26] chore: Change the expected export --- lib/dependencyConfig/DependencyConfig.ts | 14 +++++++++----- lib/dependencyConfig/setupDependencyConfig.ts | 3 ++- lib/types.ts | 4 ++-- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/dependencyConfig/DependencyConfig.ts b/lib/dependencyConfig/DependencyConfig.ts index 9f01f77..ecde744 100644 --- a/lib/dependencyConfig/DependencyConfig.ts +++ b/lib/dependencyConfig/DependencyConfig.ts @@ -1,4 +1,8 @@ -import { AutoConfigure, DeepPartial, Effects, ExpectedExports } from "../types" +import { + DependencyConfig as DependencyConfigType, + DeepPartial, + Effects, +} from "../types" import { Utils, utils } from "../util/utils" import { deepEqual } from "../util/deepEqual" import { deepMerge } from "../util/deepMerge" @@ -19,8 +23,8 @@ export class DependencyConfig< ) {} async check( - options: Parameters[0], - ): ReturnType { + options: Parameters[0], + ): ReturnType { const origConfig = JSON.parse(JSON.stringify(options.localConfig)) const newOptions = { ...options, @@ -41,8 +45,8 @@ export class DependencyConfig< throw new Error(`Check failed`) } async autoConfigure( - options: Parameters[0], - ): ReturnType { + options: Parameters[0], + ): ReturnType { const newOptions = { ...options, utils: utils(options.effects), diff --git a/lib/dependencyConfig/setupDependencyConfig.ts b/lib/dependencyConfig/setupDependencyConfig.ts index 475015b..536b257 100644 --- a/lib/dependencyConfig/setupDependencyConfig.ts +++ b/lib/dependencyConfig/setupDependencyConfig.ts @@ -1,5 +1,6 @@ import { Config } from "../config/builder/config" import { SDKManifest } from "../manifest/ManifestTypes" +import { ExpectedExports } from "../types" import { DependencyConfig } from "./DependencyConfig" export function setupDependencyConfig< @@ -17,6 +18,6 @@ export function setupDependencyConfig< any > }, -) { +): ExpectedExports.dependencyConfig { return autoConfigs } diff --git a/lib/types.ts b/lib/types.ts index 28feb6e..e6a749e 100644 --- a/lib/types.ts +++ b/lib/types.ts @@ -85,7 +85,7 @@ export namespace ExpectedExports { /** Auto configure is used to make sure that other dependencies have the values t * that this service could use. */ - export type autoConfig = Record + export type dependencyConfig = Record } export type TimeMs = number export type VersionString = string @@ -94,7 +94,7 @@ export type VersionString = string * AutoConfigure is used as the value to the key of package id, * this is used to make sure that other dependencies have the values that this service could use. */ -export type AutoConfigure = { +export type DependencyConfig = { /** Checks are called to make sure that our dependency is in the correct shape. If a known error is returned we know that the dependency needs modification */ check(options: { effects: Effects