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,
Effects,
ActionResult,
Metadata,
BackupOptions,
DeepPartial,
Address,
} from "./types"
import { Utils } from "./util/utils"
import { DependencyConfig } from "./dependencyConfig/DependencyConfig"
@@ -26,14 +26,11 @@ 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 { checkPortListening } 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 { Install, InstallFn } from "./inits/setupInstall"
import { setupActions } from "./actions/setupActions"
import { setupDependencyConfig } from "./dependencyConfig/setupDependencyConfig"
import { SetupBackupsParams, setupBackups } from "./backup/setupBackups"
@@ -49,6 +46,9 @@ import { defaultTrigger } from "./trigger/defaultTrigger"
import { changeOnFirstSuccess, cooldownTrigger } from "./trigger"
import setupConfig, { Read, Save } from "./config/setupConfig"
import { setupDependencyMounts } from "./dependency/setupDependencyMounts"
import { SetInterfaces, setupInterfaces } from "./interfaces/setupInterfaces"
import { AddressReceipt } from "./interfaces/AddressReceipt"
import { Host } from "./interfaces/Host"
// prettier-ignore
type AnyNeverCond<T extends any[], Then, Else> =
@@ -155,8 +155,17 @@ export class StartSdk<Manifest extends SDKManifest, Store, Vault> {
migrations: Migrations<Store, Vault>,
install: Install<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),
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: (
fn: (o: {
effects: Effects

View File

@@ -4,7 +4,8 @@ import * as D from "./configDependencies"
import { Config, ExtractConfigType } from "./builder/config"
import { Utils, utils } from "../util/utils"
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
export type DependenciesReceipt = void & {
@@ -27,6 +28,7 @@ export type Save<
}) => Promise<{
dependenciesReceipt: DependenciesReceipt
interfaceReceipt: InterfaceReceipt
setInterfacesReceipt: SetInterfacesReceipt
restart: boolean
}>
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 { CheckResult } from "./checkFns/CheckResult"
import { HealthReceipt } from "./HealthReceipt"

View File

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

View File

@@ -1,6 +1,5 @@
import { object, string } from "ts-matches"
import { Effects } from "../types"
import { NetworkInterfaceBuilder } from "./NetworkInterfaceBuilder"
import { Origin } from "./Origin"
const knownProtocols = {
@@ -94,9 +93,9 @@ const hasStringProtocal = object({
export class Host {
constructor(
readonly kind: "static" | "single" | "multi",
readonly options: {
effects: Effects
kind: "static" | "single" | "multi"
id: string
},
) {}
@@ -127,7 +126,7 @@ export class Host {
} & { secure: true; ssl: boolean }),
) {
await this.options.effects.bind({
kind: this.kind,
kind: this.options.kind,
id: this.options.id,
internalPort: internalPort,
...options,
@@ -163,7 +162,7 @@ export class Host {
}
await this.options.effects.bind({
kind: this.kind,
kind: this.options.kind,
id: this.options.id,
internalPort,
...newOptions,
@@ -189,35 +188,18 @@ export class Host {
export class StaticHost extends Host {
constructor(options: { effects: Effects; id: string }) {
super("static", options)
super({ ...options, kind: "static" })
}
}
export class SingleHost extends Host {
constructor(options: { effects: Effects; id: string }) {
super("single", options)
super({ ...options, kind: "single" })
}
}
export class MultiHost extends Host {
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 { Host } from "./Host"
import { Origin } from "./Origin"
@@ -36,7 +36,9 @@ export class NetworkInterfaceBuilder {
* @param addresses
* @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 addresses = Array.from(origins).map((o) =>
@@ -51,6 +53,6 @@ export class NetworkInterfaceBuilder {
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 { defaultTrigger } from "../trigger/defaultTrigger"
import { DaemonReturned, Effects, ValidIfNoStupidEscape } from "../types"
import { InterfaceReceipt } from "./interfaceReceipt"
type Daemon<Ids extends string, Command extends string, Id extends string> = {
id: "" extends Id ? never : Id
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 { Utils, utils } from "../util/utils"
import { Daemons } from "./Daemons"
import "./exportInterfaces"
import "./LocalBinding"
import "./LocalPort"
import "./NetworkBuilder"
import "./NetworkInterfaceBuilder"
import "./Origin"
import "./TorBinding"
import "./TorHostname"
import "../interfaces/NetworkInterfaceBuilder"
import "../interfaces/Origin"
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"
import { InputSpec } from "./config/configTypes"
import { DependenciesReceipt } from "./config/setupConfig"
import { PortOptions } from "./mainFn/Host"
import { PortOptions } from "./interfaces/Host"
export type ExportedAction = (options: {
effects: Effects

View File

@@ -8,10 +8,6 @@ import {
} 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"
@@ -26,36 +22,9 @@ import {
NamedPath,
Path,
} from "../dependency/setupDependencyMounts"
import { Host, MultiHost, SingleHost, StaticHost } from "../interfaces/Host"
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(
port: number,
options: {
@@ -73,10 +42,18 @@ export type Utils<Store, Vault, WrapperOverWrite = { const: never }> = {
errorMessage?: string
},
): Promise<CheckResult>
bindLan: (port: number) => Promise<LocalBinding>
networkBuilder: () => NetworkBuilder
torHostName: (id: string) => TorHostname
nullIfEmpty: typeof nullIfEmpty
createOrUpdateVault: (opts: {
key: string
value: string | null | undefined
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: <
In extends
| Record<ManifestId, Record<VolumeName, Record<NamedPath, Path>>>
@@ -86,6 +63,29 @@ export type Utils<Store, Vault, WrapperOverWrite = { const: never }> = {
>(
value: 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 = <
Store = never,
@@ -116,6 +116,16 @@ export const utils = <
},
getSystemSmtp: () =>
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),
writeFile: <A>(fileHelper: FileHelper<A>, data: A) =>
fileHelper.write(data, effects),
@@ -137,10 +147,6 @@ export const utils = <
},
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),
vault: {
get: (key: keyof Vault & string) =>
getVault<Vault>(effects, key) as GetVault<Vault> & WrapperOverWrite,