mirror of
https://github.com/Start9Labs/start-sdk.git
synced 2026-03-26 10:21:55 +00:00
feat: Create the setupInterfaces types
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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<
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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])
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
27
lib/interfaces/setupInterfaces.ts
Normal file
27
lib/interfaces/setupInterfaces.ts
Normal 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
|
||||
@@ -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[]]
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
export declare const ReadyProof: unique symbol
|
||||
export type ReadyReceipt = {
|
||||
[ReadyProof]: never
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
import { Daemon } from "../types"
|
||||
import { ReadyProof } from "./ReadyProof"
|
||||
|
||||
export type RunningMainRet = {
|
||||
[ReadyProof]: never
|
||||
daemon: Daemon
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
27
lib/test/host.test.ts
Normal 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])
|
||||
}
|
||||
})
|
||||
})
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user