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 +}