feat: Create the setupInterfaces types

This commit is contained in:
BluJ
2023-05-11 14:50:40 -06:00
parent 97701967b7
commit ed56e39f00
21 changed files with 142 additions and 148 deletions

View File

@@ -16,9 +16,9 @@ import {
ActionMetadata, ActionMetadata,
Effects, Effects,
ActionResult, ActionResult,
Metadata,
BackupOptions, BackupOptions,
DeepPartial, DeepPartial,
Address,
} from "./types" } from "./types"
import { Utils } from "./util/utils" import { Utils } from "./util/utils"
import { DependencyConfig } from "./dependencyConfig/DependencyConfig" import { DependencyConfig } from "./dependencyConfig/DependencyConfig"
@@ -26,14 +26,11 @@ import { BackupSet, Backups } from "./backup/Backups"
import { smtpConfig } from "./config/configConstants" import { smtpConfig } from "./config/configConstants"
import { Daemons } from "./mainFn/Daemons" import { Daemons } from "./mainFn/Daemons"
import { healthCheck } from "./health/HealthCheck" import { healthCheck } from "./health/HealthCheck"
import { import { checkPortListening } from "./health/checkFns/checkPortListening"
checkPortListening,
containsAddress,
} from "./health/checkFns/checkPortListening"
import { checkWebUrl, runHealthScript } from "./health/checkFns" import { checkWebUrl, runHealthScript } from "./health/checkFns"
import { List } from "./config/builder/list" import { List } from "./config/builder/list"
import { Migration } from "./inits/migrations/Migration" import { Migration } from "./inits/migrations/Migration"
import { Install, InstallFn, setupInstall } from "./inits/setupInstall" import { Install, InstallFn } from "./inits/setupInstall"
import { setupActions } from "./actions/setupActions" import { setupActions } from "./actions/setupActions"
import { setupDependencyConfig } from "./dependencyConfig/setupDependencyConfig" import { setupDependencyConfig } from "./dependencyConfig/setupDependencyConfig"
import { SetupBackupsParams, setupBackups } from "./backup/setupBackups" import { SetupBackupsParams, setupBackups } from "./backup/setupBackups"
@@ -49,6 +46,9 @@ import { defaultTrigger } from "./trigger/defaultTrigger"
import { changeOnFirstSuccess, cooldownTrigger } from "./trigger" import { changeOnFirstSuccess, cooldownTrigger } from "./trigger"
import setupConfig, { Read, Save } from "./config/setupConfig" import setupConfig, { Read, Save } from "./config/setupConfig"
import { setupDependencyMounts } from "./dependency/setupDependencyMounts" import { setupDependencyMounts } from "./dependency/setupDependencyMounts"
import { SetInterfaces, setupInterfaces } from "./interfaces/setupInterfaces"
import { AddressReceipt } from "./interfaces/AddressReceipt"
import { Host } from "./interfaces/Host"
// prettier-ignore // prettier-ignore
type AnyNeverCond<T extends any[], Then, Else> = type AnyNeverCond<T extends any[], Then, Else> =
@@ -155,8 +155,17 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
migrations: Migrations<Store, Vault>, migrations: Migrations<Store, Vault>,
install: Install<Store, Vault>, install: Install<Store, Vault>,
uninstall: Uninstall<Store, Vault>, uninstall: Uninstall<Store, Vault>,
) => setupInit<Store, Vault>(migrations, install, uninstall), setInterfaces: SetInterfaces<Store, Vault, any, any>,
) =>
setupInit<Store, Vault>(migrations, install, uninstall, setInterfaces),
setupInstall: (fn: InstallFn<Store, Vault>) => Install.of(fn), setupInstall: (fn: InstallFn<Store, Vault>) => Install.of(fn),
setupInterfaces: <
ConfigInput extends Record<string, any>,
Output extends Record<string, Address[] & AddressReceipt>,
>(
config: Config<ConfigInput, Store, Vault>,
fn: SetInterfaces<Store, Vault, ConfigInput, Output>,
) => setupInterfaces(config, fn),
setupMain: ( setupMain: (
fn: (o: { fn: (o: {
effects: Effects effects: Effects

View File

@@ -4,7 +4,8 @@ import * as D from "./configDependencies"
import { Config, ExtractConfigType } from "./builder/config" import { Config, ExtractConfigType } from "./builder/config"
import { Utils, utils } from "../util/utils" import { Utils, utils } from "../util/utils"
import nullIfEmpty from "../util/nullIfEmpty" import nullIfEmpty from "../util/nullIfEmpty"
import { InterfaceReceipt } from "../mainFn/interfaceReceipt" import { InterfaceReceipt } from "../interfaces/interfaceReceipt"
import { SetInterfacesReceipt } from "../interfaces/setupInterfaces"
declare const dependencyProof: unique symbol declare const dependencyProof: unique symbol
export type DependenciesReceipt = void & { export type DependenciesReceipt = void & {
@@ -27,6 +28,7 @@ export type Save<
}) => Promise<{ }) => Promise<{
dependenciesReceipt: DependenciesReceipt dependenciesReceipt: DependenciesReceipt
interfaceReceipt: InterfaceReceipt interfaceReceipt: InterfaceReceipt
setInterfacesReceipt: SetInterfacesReceipt
restart: boolean restart: boolean
}> }>
export type Read< export type Read<

View File

@@ -1,4 +1,4 @@
import { InterfaceReceipt } from "../mainFn/interfaceReceipt" import { InterfaceReceipt } from "../interfaces/interfaceReceipt"
import { Daemon, Effects } from "../types" import { Daemon, Effects } from "../types"
import { CheckResult } from "./checkFns/CheckResult" import { CheckResult } from "./checkFns/CheckResult"
import { HealthReceipt } from "./HealthReceipt" import { HealthReceipt } from "./HealthReceipt"

View File

@@ -1,4 +1,6 @@
import { SetInterfaces } from "../interfaces/setupInterfaces"
import { ExpectedExports } from "../types" import { ExpectedExports } from "../types"
import { createUtils } from "../util"
import { Migrations } from "./migrations/setupMigrations" import { Migrations } from "./migrations/setupMigrations"
import { Install } from "./setupInstall" import { Install } from "./setupInstall"
import { Uninstall } from "./setupUninstall" import { Uninstall } from "./setupUninstall"
@@ -7,6 +9,7 @@ export function setupInit<Store, Vault>(
migrations: Migrations<Store, Vault>, migrations: Migrations<Store, Vault>,
install: Install<Store, Vault>, install: Install<Store, Vault>,
uninstall: Uninstall<Store, Vault>, uninstall: Uninstall<Store, Vault>,
setInterfaces: SetInterfaces<Store, Vault, any, any>,
): { ): {
init: ExpectedExports.init init: ExpectedExports.init
uninit: ExpectedExports.uninit uninit: ExpectedExports.uninit
@@ -15,6 +18,11 @@ export function setupInit<Store, Vault>(
init: async (opts) => { init: async (opts) => {
await migrations.init(opts) await migrations.init(opts)
await install.init(opts) await install.init(opts)
await setInterfaces({
...opts,
input: null,
utils: createUtils<Store, Vault>(opts.effects),
})
}, },
uninit: async (opts) => { uninit: async (opts) => {
await migrations.uninit(opts) await migrations.uninit(opts)

View File

@@ -1,6 +1,5 @@
import { object, string } from "ts-matches" import { object, string } from "ts-matches"
import { Effects } from "../types" import { Effects } from "../types"
import { NetworkInterfaceBuilder } from "./NetworkInterfaceBuilder"
import { Origin } from "./Origin" import { Origin } from "./Origin"
const knownProtocols = { const knownProtocols = {
@@ -94,9 +93,9 @@ const hasStringProtocal = object({
export class Host { export class Host {
constructor( constructor(
readonly kind: "static" | "single" | "multi",
readonly options: { readonly options: {
effects: Effects effects: Effects
kind: "static" | "single" | "multi"
id: string id: string
}, },
) {} ) {}
@@ -127,7 +126,7 @@ export class Host {
} & { secure: true; ssl: boolean }), } & { secure: true; ssl: boolean }),
) { ) {
await this.options.effects.bind({ await this.options.effects.bind({
kind: this.kind, kind: this.options.kind,
id: this.options.id, id: this.options.id,
internalPort: internalPort, internalPort: internalPort,
...options, ...options,
@@ -163,7 +162,7 @@ export class Host {
} }
await this.options.effects.bind({ await this.options.effects.bind({
kind: this.kind, kind: this.options.kind,
id: this.options.id, id: this.options.id,
internalPort, internalPort,
...newOptions, ...newOptions,
@@ -189,35 +188,18 @@ export class Host {
export class StaticHost extends Host { export class StaticHost extends Host {
constructor(options: { effects: Effects; id: string }) { constructor(options: { effects: Effects; id: string }) {
super("static", options) super({ ...options, kind: "static" })
} }
} }
export class SingleHost extends Host { export class SingleHost extends Host {
constructor(options: { effects: Effects; id: string }) { constructor(options: { effects: Effects; id: string }) {
super("single", options) super({ ...options, kind: "single" })
} }
} }
export class MultiHost extends Host { export class MultiHost extends Host {
constructor(options: { effects: Effects; id: string }) { constructor(options: { effects: Effects; id: string }) {
super("multi", options) super({ ...options, kind: "multi" })
} }
} }
async function test(effects: Effects) {
const foo = new MultiHost({ effects, id: "foo" })
const fooOrigin = await foo.bindPort(80, { protocol: "http" as const })
const fooInterface = new NetworkInterfaceBuilder({
effects,
name: "Foo",
id: "foo",
description: "A Foo",
ui: true,
username: "bar",
path: "/baz",
search: { qux: "yes" },
})
await fooInterface.export([fooOrigin])
}

View File

@@ -1,4 +1,4 @@
import { Effects } from "../types" import { Address, Effects } from "../types"
import { AddressReceipt } from "./AddressReceipt" import { AddressReceipt } from "./AddressReceipt"
import { Host } from "./Host" import { Host } from "./Host"
import { Origin } from "./Origin" import { Origin } from "./Origin"
@@ -36,7 +36,9 @@ export class NetworkInterfaceBuilder {
* @param addresses * @param addresses
* @returns * @returns
*/ */
async export(origins: Iterable<Origin<Host>>) { async export<Origins extends Origin<Host>[]>(
origins: Origins,
): Promise<Address[] & AddressReceipt> {
const { name, description, id, ui, username, path, search } = this.options const { name, description, id, ui, username, path, search } = this.options
const addresses = Array.from(origins).map((o) => const addresses = Array.from(origins).map((o) =>
@@ -51,6 +53,6 @@ export class NetworkInterfaceBuilder {
ui, ui,
}) })
return {} as AddressReceipt return addresses as Address[] & AddressReceipt
} }
} }

View File

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

View File

@@ -4,7 +4,6 @@ import { Trigger } from "../trigger"
import { TriggerInput } from "../trigger/TriggerInput" import { TriggerInput } from "../trigger/TriggerInput"
import { defaultTrigger } from "../trigger/defaultTrigger" import { defaultTrigger } from "../trigger/defaultTrigger"
import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types" import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types"
import { InterfaceReceipt } from "./interfaceReceipt"
type Daemon<Ids extends string, Command extends string, Id extends string> = { type Daemon<Ids extends string, Command extends string, Id extends string> = {
id: "" extends Id ? never : Id id: "" extends Id ? never : Id
command: ValidIfNoStupidEscape<Command> | [string, ...string[]] command: ValidIfNoStupidEscape<Command> | [string, ...string[]]

View File

@@ -1,13 +0,0 @@
import { Effects } from "../types"
import { TorHostname } from "./TorHostname"
export class NetworkBuilder {
static of(effects: Effects) {
return new NetworkBuilder(effects)
}
private constructor(private effects: Effects) {}
getTorHostName(id: string) {
return new TorHostname(this.effects, id)
}
}

View File

@@ -1,4 +0,0 @@
export declare const ReadyProof: unique symbol
export type ReadyReceipt = {
[ReadyProof]: never
}

View File

@@ -1,7 +0,0 @@
import { Daemon } from "../types"
import { ReadyProof } from "./ReadyProof"
export type RunningMainRet = {
[ReadyProof]: never
daemon: Daemon
}

View File

@@ -1,8 +0,0 @@
import { Origin } from "./Origin"
export class TorBinding {
constructor(readonly host: string) {}
createOrigin(protocol: string | null) {
return new Origin(protocol, this.host)
}
}

View File

@@ -1,17 +0,0 @@
import { Effects } from "../types"
import { TorBinding } from "./TorBinding"
export class TorHostname {
constructor(readonly effects: Effects, readonly id: string) {}
static of(effects: Effects, id: string) {
return new TorHostname(effects, id)
}
async bindTor(internalPort: number, externalPort: number) {
const address = await this.effects.bindTor({
internalPort,
name: this.id,
externalPort,
})
return new TorBinding(address)
}
}

View File

@@ -1,13 +0,0 @@
import { AddressReceipt } from "./AddressReceipt"
import { InterfaceReceipt } from "./interfaceReceipt"
/**
* Takes a list of addressReceipts
*
* Returns an interfaceReceipt, which is needed to create the service daemons
*/
export const exportInterfaces = (
_firstProof: AddressReceipt,
..._rest: AddressReceipt[]
) => ({} as InterfaceReceipt)
export default exportInterfaces

View File

@@ -2,14 +2,8 @@ import { Effects, ExpectedExports } from "../types"
import { createMainUtils } from "../util" import { createMainUtils } from "../util"
import { Utils, utils } from "../util/utils" import { Utils, utils } from "../util/utils"
import { Daemons } from "./Daemons" import { Daemons } from "./Daemons"
import "./exportInterfaces" import "../interfaces/NetworkInterfaceBuilder"
import "./LocalBinding" import "../interfaces/Origin"
import "./LocalPort"
import "./NetworkBuilder"
import "./NetworkInterfaceBuilder"
import "./Origin"
import "./TorBinding"
import "./TorHostname"
import "./Daemons" import "./Daemons"

27
lib/test/host.test.ts Normal file
View File

@@ -0,0 +1,27 @@
import { MultiHost } from "../interfaces/Host"
import { NetworkInterfaceBuilder } from "../interfaces/NetworkInterfaceBuilder"
import { Effects } from "../types"
import { createUtils } from "../util"
import { sdk } from "./output.sdk"
describe("host", () => {
test("Testing that the types work", () => {
async function test(effects: Effects) {
const utils = createUtils<never, never>(effects)
const foo = utils.host.multi({ id: "foo" })
const fooOrigin = await foo.bindPort(80, { protocol: "http" as const })
const fooInterface = new NetworkInterfaceBuilder({
effects,
name: "Foo",
id: "foo",
description: "A Foo",
ui: true,
username: "bar",
path: "/baz",
search: { qux: "yes" },
})
await fooInterface.export([fooOrigin])
}
})
})

View File

@@ -1,7 +1,7 @@
export * as configTypes from "./config/configTypes" export * as configTypes from "./config/configTypes"
import { InputSpec } from "./config/configTypes" import { InputSpec } from "./config/configTypes"
import { DependenciesReceipt } from "./config/setupConfig" import { DependenciesReceipt } from "./config/setupConfig"
import { PortOptions } from "./mainFn/Host" import { PortOptions } from "./interfaces/Host"
export type ExportedAction = (options: { export type ExportedAction = (options: {
effects: Effects effects: Effects

View File

@@ -8,10 +8,6 @@ import {
} from "../health/checkFns" } from "../health/checkFns"
import { ExtractStore } from "../types" import { ExtractStore } from "../types"
import { GetSystemSmtp } from "./GetSystemSmtp" 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 { DefaultString } from "../config/configTypes"
import { getDefaultString } from "./getDefaultString" import { getDefaultString } from "./getDefaultString"
import { GetStore, getStore } from "../store/getStore" import { GetStore, getStore } from "../store/getStore"
@@ -26,36 +22,9 @@ import {
NamedPath, NamedPath,
Path, Path,
} from "../dependency/setupDependencyMounts" } from "../dependency/setupDependencyMounts"
import { Host, MultiHost, SingleHost, StaticHost } from "../interfaces/Host"
export type Utils<Store, Vault, WrapperOverWrite = { const: never }> = { export type Utils<Store, Vault, WrapperOverWrite = { const: never }> = {
createOrUpdateVault: (opts: {
key: string
value: string | null | undefined
generator: DefaultString
}) => Promise<null | string>
readFile: <A>(fileHelper: FileHelper<A>) => ReturnType<FileHelper<A>["read"]>
writeFile: <A>(
fileHelper: FileHelper<A>,
data: A,
) => ReturnType<FileHelper<A>["write"]>
getSystemSmtp: () => GetSystemSmtp & WrapperOverWrite
store: {
get: <Path extends string>(
packageId: string,
path: T.EnsureStorePath<Store, Path>,
) => GetStore<Store, Path> & WrapperOverWrite
getOwn: <Path extends string>(
path: T.EnsureStorePath<Store, Path>,
) => GetStore<Store, Path> & WrapperOverWrite
setOwn: <Path extends string | never>(
path: T.EnsureStorePath<Store, Path>,
value: ExtractStore<Store, Path>,
) => Promise<void>
}
vault: {
get: (key: keyof Vault & string) => GetVault<Vault> & WrapperOverWrite
set: (key: keyof Vault & string, value: string) => Promise<void>
}
checkPortListening( checkPortListening(
port: number, port: number,
options: { options: {
@@ -73,10 +42,18 @@ export type Utils<Store, Vault, WrapperOverWrite = { const: never }> = {
errorMessage?: string errorMessage?: string
}, },
): Promise<CheckResult> ): Promise<CheckResult>
bindLan: (port: number) => Promise<LocalBinding> createOrUpdateVault: (opts: {
networkBuilder: () => NetworkBuilder key: string
torHostName: (id: string) => TorHostname value: string | null | undefined
nullIfEmpty: typeof nullIfEmpty generator: DefaultString
}) => Promise<null | string>
getSystemSmtp: () => GetSystemSmtp & WrapperOverWrite
host: {
of: (options: { kind: "static" | "single" | "multi"; id: string }) => Host
static: (options: { id: string }) => StaticHost
single: (options: { id: string }) => SingleHost
multi: (options: { id: string }) => MultiHost
}
mountDependencies: < mountDependencies: <
In extends In extends
| Record<ManifestId, Record<VolumeName, Record<NamedPath, Path>>> | Record<ManifestId, Record<VolumeName, Record<NamedPath, Path>>>
@@ -86,6 +63,29 @@ export type Utils<Store, Vault, WrapperOverWrite = { const: never }> = {
>( >(
value: In, value: In,
) => Promise<MountDependenciesOut<In>> ) => Promise<MountDependenciesOut<In>>
nullIfEmpty: typeof nullIfEmpty
readFile: <A>(fileHelper: FileHelper<A>) => ReturnType<FileHelper<A>["read"]>
store: {
get: <Path extends string>(
packageId: string,
path: T.EnsureStorePath<Store, Path>,
) => GetStore<Store, Path> & WrapperOverWrite
getOwn: <Path extends string>(
path: T.EnsureStorePath<Store, Path>,
) => GetStore<Store, Path> & WrapperOverWrite
setOwn: <Path extends string | never>(
path: T.EnsureStorePath<Store, Path>,
value: ExtractStore<Store, Path>,
) => Promise<void>
}
vault: {
get: (key: keyof Vault & string) => GetVault<Vault> & WrapperOverWrite
set: (key: keyof Vault & string, value: string) => Promise<void>
}
writeFile: <A>(
fileHelper: FileHelper<A>,
data: A,
) => ReturnType<FileHelper<A>["write"]>
} }
export const utils = < export const utils = <
Store = never, Store = never,
@@ -116,6 +116,16 @@ export const utils = <
}, },
getSystemSmtp: () => getSystemSmtp: () =>
new GetSystemSmtp(effects) as GetSystemSmtp & WrapperOverWrite, new GetSystemSmtp(effects) as GetSystemSmtp & WrapperOverWrite,
host: {
of: (options: { kind: "static" | "single" | "multi"; id: string }) =>
new Host({ ...options, effects }),
static: (options: { id: string }) =>
new StaticHost({ ...options, effects }),
single: (options: { id: string }) =>
new SingleHost({ ...options, effects }),
multi: (options: { id: string }) => new MultiHost({ ...options, effects }),
},
readFile: <A>(fileHelper: FileHelper<A>) => fileHelper.read(effects), readFile: <A>(fileHelper: FileHelper<A>) => fileHelper.read(effects),
writeFile: <A>(fileHelper: FileHelper<A>, data: A) => writeFile: <A>(fileHelper: FileHelper<A>, data: A) =>
fileHelper.write(data, effects), fileHelper.write(data, effects),
@@ -137,10 +147,6 @@ export const utils = <
}, },
checkPortListening: checkPortListening.bind(null, effects), checkPortListening: checkPortListening.bind(null, effects),
checkWebUrl: checkWebUrl.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),
vault: { vault: {
get: (key: keyof Vault & string) => get: (key: keyof Vault & string) =>
getVault<Vault>(effects, key) as GetVault<Vault> & WrapperOverWrite, getVault<Vault>(effects, key) as GetVault<Vault> & WrapperOverWrite,